【问题标题】:cost of Async.StartAsync.Start 的成本
【发布时间】:2012-04-02 08:52:41
【问题描述】:

在邮箱处理器循环中,我从阻塞集合中读取先前存储在此类集合中的项目。由于我使用相同的循环来写入此类集合,因此我需要将其作为线程启动。

async { process(queue.Take()) } |> Aysync.Start

我的整个代码的执行速度很慢(相对而言),我怀疑原因是我启动了新线程,尽管我用启动线程池

let toto = ThreadPool.SetMinThreads(300,300)

争点可能在这里的另一个提示是,如果我仅在队列为空时启动(并锁定整个部分)),我的运行时间差异很大,从 350 毫秒到 7 秒,而如果不这样做,它会停留大约 5-10 秒。

我的问题是:

  • 有没有我可以在这里加速线程的创建
  • 是否有一些结构已经处理了这种情况(消费者/生产者?),可以在邮箱处理器中使用?

【问题讨论】:

  • 不要猜测你的性能问题在哪里,测量它!您可以使用分析器来执行此操作。
  • 非常好的观点。我也坚信先测量后优化,我想我应该应用它。你能把它转移到答案吗? (因为我发现了 dotnet + fsharp 的东西,所以我对进行分析的好工具知之甚少……任何建议表示赞赏)
  • @nicolas - 为什么有这么多线程。我怀疑你会在大约 20 个线程时更快地发现事情(如果你受 CPU 限制,甚至更少)
  • 就我而言,我是 IO 受限的。昨天之前我不知道 SetMinThreads(如果我排除了我在 5 年前知道的所有内容:))并且遇到了一个案例,它是缓慢的根源,所以谁知道..
  • 我认为 svick 有一个优点:在优化之前,应该进行测量。这可能只是我调用的 IO 系统的一些缓慢的影响。我的计算运行时间从 400 毫秒到 20 秒。所以我的问题首先是不恰当的。

标签: multithreading f# async-await mailboxprocessor


【解决方案1】:

如果您需要创建数百个线程来运行 I/O 绑定计算,那么可能有问题。如果计算是 I/O 绑定的,那么应该可以使用相对较少数量的线程来运行它 - 如果它是完全异步,则意味着线程在任何等待期间都不会被阻塞。

所以,我认为在你的程序中首先要寻找的是线程被阻塞的地方,并用异步等待代替。

您的代码示例中的一个可疑之处是队列,当您调用Take 时,它可能会阻塞,至少,这就是.NET 中BlockingCollection 的行为方式。您可以尝试将其替换为 BlockingQueueAgent,它使用 F# 代理实现相同的功能,但提供了可以在不阻塞线程的情况下调用的异步 AsyncTake 方法。

【讨论】:

  • 我好像重新实现了BlockingQueueAgent。这不是那么简单。至少我学到了很多。
  • 确实减少了线程数添加没有影响。在我设置它的时候,我确实看到了一个太小的池 (stackoverflow.com/questions/9955960/cost-of-runsynchronously) 的影响,所以将它设置为一个较高的数字。在这里减少它几乎没有影响,所以'pb'在别处。除了您对 BlockingQueueAgent 的有用提示之外,您还推荐使用哪种工具先测量,然后再进行优化?
  • tomas,我希望您为我使用线程和有关它们的旧知识重新实现邮箱代理并完全忽略您精心设计的邮箱代理感到抱歉。
猜你喜欢
  • 1970-01-01
  • 2019-07-25
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 1970-01-01
  • 2013-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多