在任务上指定 LongRunning 有多重要?

How important is it to specify LongRunning on a Task?

How to pass LongRunning flag specifically to Task.Run()? 强调将任务创建标志放入较新的 API 中可能有点混乱,尤其是使用 async 模式。

我发现这篇文章声称无论如何 async 都不是一个好主意,不应该使用:http://blog.i3arnon.com/2015/07/02/task-run-long-running/

我的理解是,这个标志在实践中会导致 TPL 启动一个专用线程,而不是对线程池施加压力,但特别是如果我的应用程序不涉及大量并行任务,这真的很重要吗?如果我预期的并行度小于默认线程池大小(无论是什么),我是否可以安全地省略该标志 - 最糟糕的情况是线程池可能会在几百毫秒内缺乏线程?

线程池背后的整个想法是创建任务需要几毫秒,因为它要求 OS 创建它,切换上下文等等......所以为了处理它,框架创建一些池,并将用过的线程放在那里以备后用...

你是对的,LongRunning 标志很可能会导致创建新线程...当新任务将花费更长的时间并且线程创建时间在其中并不重要时,这是有意义的。

线程池有一定的算法,如果你从那里集中取出很多线程并让它们忙碌,它可能会决定将线程数量加倍 假设您要占用越来越多的资源……因此,如果您要让线程池中的线程足够长的时间忙碌,您将不会从线程池中获得任何好处,而是会得到一些开销。

因此忽略该标志不会破坏任何东西,但可能会带来一些开销。

调用Task.Factory.StartNew方法而不传递TaskCreationOptions参数时,默认省略LongRunning标志,因此您可以放心地假设省略它是安全的。实际上,省略它比包含它更安全,因为这个标志旨在作为一种性能优化技术,而不是日常用品。

In general, don't use it unless you find that you really need it. You'd typically only use LongRunning if you found through performance testing that not using it was causing long delays in the processing of other work. (citation)

如果 ThreadPool 因为它的线程被滥用(在等待 I/O 操作完成时被阻塞)而经常被饿死,那么不要装饰你的所有 Task如果使用 LongRunning 标志,一个更简单、更有效的解决方法可能是在应用程序初始化期间使用方法 ThreadPool.SetMinThreads 增加 ThreadPool 线程的最小数量。例如:

ThreadPool.SetMinThreads(workerThreads: 100, completionPortThreads: 5);

当您重构应用程序以正确使用异步时,撤消此 hack 会更容易,而不是撤消代码中各处的 LongRunning 标志。