【问题标题】:How are multiple requests to Task.Run handled from a resource management standpoint?从资源管理的角度来看,如何处理对 Task.Run 的多个请求?
【发布时间】:2015-06-07 20:20:28
【问题描述】:

我有一些代码需要“触发并忘记”,因为调用代码不需要等待响应。

如果我要迭代一个循环并在一秒钟内调用它 10,000 次,我是否会有 10,000 个线程在四处游荡,争夺资源?我做了一个噩梦,我的机器立刻慢了下来。

或者,线程池是否管理这些请求,并将它们排队等待解决?

换句话说,用Task.Run()做一些愚蠢的事情是多么容易。

【问题讨论】:

  • 试一试,线程池的工作原理就会一目了然。
  • 10,000 个线程你在做什么?什么样的工作?

标签: c# .net multithreading asynchronous task-parallel-library


【解决方案1】:

因此,当您调用 Task.Run 时,它会创建一个新的 Task 并将其安排在 TaskScheduler.Default 上。那恰好是ThreadPoolTaskScheduler,然后将该任务排队到ThreadPoolThreadPool 使用线程池(令人惊讶地)缓慢地通过工作项。 ThreadPool 在内部管理自己的线程,并且可以在需要时创建更多线程。

你的问题:

我会不会有 10,000 个线程四处游荡,争夺资源?

不,ThreadPool 通常知道如何有效地管理其线程并且增长非常缓慢。

但是,您分配大量任务,这些任务会在那里等待占用空间直到完成。他们也可能会保留占用资源的其他引用(通常是因为捕获)。


顺便说一句,如果您使用Task.Factory.StartNew 并传递TaskCreationOptions.LongRunning 而不是更安全的Task.Run,那么您创建 10,000 个后台线程。

【讨论】:

  • 那么,你是说我基本上可以相信线程池让我免于麻烦?
  • @Deane 不是真的。我是说你不应该因为线程以外的原因这样做。查看 TPL 数据流的 ActionBlock 或其他更高级别的构造。
【解决方案2】:

当您调用 Task.Run 时,您正在排队工作以在线程池中运行。如果您开始大量工作,则可能需要一段时间才能完成,因为您的计算资源有限。使用 Task.Run 运行后台任务时很容易咬自己。最好了解场景并为工作使用正确的工具。如果您希望处理大量后台工作,请查看 TPL、BlockingCollection 和并发集合等内容。像生产者/消费者流这样的事情是正确的方向,但这一切都取决于您要解决的问题。

【讨论】:

  • 在这种情况下,我并不关心工作何时完成,只要它真正完成即可。所以线程池可以在它上面坐几分钟,如果它愿意的话,只要它最终到达它。
  • 虽然您可能不关心安排一堆任务,但您可能没有以正确的方式做事。如果通过调度所有这些任务,您使用了比需要更多的内存、引入了死锁或内存泄漏怎么办?在可能无关紧要的事情上以正确的方式解决问题会让你在以后解决重要的事情上做得更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-12
  • 2014-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多