何时使用TaskCreationOptions.LongRunning?

我很想知道这一点,但从未真正找到答案。

我知道这是任务调度程序的一个提示,任务调度程序将在其中运行,并且任务调度程序可以(或现在将?)决定为该任务实例化非线程池线程。

我不知道(并且令人惊讶地在互联网上找不到)是一些“经验法则”何时将任务指定为长时间运行。 是一秒多长? 30秒? 一分钟? 5分钟? 它是否与应用程序使用的任务量有关系? 作为程序员,我应该使用线程池中的#threads进行一些计算,我创建了多少个任务,同时长时间运行了多少个任务,并根据这个来决定是否使用长时间运行的任务?

希望在这里学点东西。

它可以量化,当现有的tp线程不能很快完成时,线程池管理器会添加一个超出最佳值的额外线程。 它每秒执行两次,直到SetMaxThreads()设置的最大值。 其中默认值非常高。 最佳的是机器可用的处理器核心数,4是典型的。 由于上下文切换开销,运行比可用核心更多的线程可能是有害的。

它是基于这些现有线程没有取得进展的假设 ,因为它们没有执行足够的代码。 换句话说,它们会阻塞I / O或锁定太多。 因此,这样的线程不能足够有效地使用核心,并且允许额外的线程执行完全适合于提高处理器使用率并完成更多工作。

因此,当线程占用超过半秒时,它就是“长时间运行”。 请记住,这是一个很长的时间,它相当于现代桌面类机器上大约40亿处理器指令。 除非你运行计算量很大的代码,比如将pi的值计算到数千亿的数字,从而实际执行那些40亿条指令,否则一个实际的线程只能在它过于频繁地阻塞时花费很长时间。 这是非常常见的,像dbase查询这样的东西通常很慢并且在工作线程上执行并且消耗很少的cpu。

否则,您需要validation线程池管理器所做的假设是否准确。 该任务应该花费很长时间,因为它没有有效地使用处理器。 任务管理器是一种简单的方法,可以查看处理器内核在您的程序中正在执行的操作,尽管它不会准确地告诉您它们正在执行的代码。 您需要进行unit testing才能看到线程是独立执行的。 最终且唯一完全准确的方式告诉您使用LongRunning是一个合适的选择是validation您的应用程序确实完成了更多的工作。

修改汉斯的回答,我大多赞同。

指定LongRunning的最重要原因是获得实际保证且几乎立即执行。 不会有任何等待线程池向您的工作项发出线程。 我说的是“实际上”,因为操作系统可以自由安排你的线程。 但是你会得到一些CPU的份额,通常不会花很长时间才能发生。

你通过指定LongRunning跳到队列LongRunning 。 如果线程池处于负载状态,则无需等待线程池每秒发出2个线程。

因此,您可以将LongRunning用于必须以最有效的方式但必须以及时和稳定的方式发生的事情。 例如,一些UI工作,游戏循环,进度报告,……

启动和停止线程的成本大约为1ms的CPU时间。 这远远超过发布线程池工作项。 我只是将此基准测试为每秒发布和完成的3M项目。 基准是非常人为的,但数量级是正确的。

LongRunning是一个提示,但它在实践中绝对有效。 没有启发式将您的提示考虑在内。 它被认为是正确的。

何时将任务指定为长时间运行

这取决于任务正在做什么。 如果task包含while(true) {...}并且直到应用程序关闭,那么指定LongRunning 。 如果您创建任务以排队某些操作并阻止阻止当前线程,那么您并不关心(不要指定任何内容)。

这取决于其他任务正在做什么。 如果您使用或不使用LongRunning运行少量任务并不LongRunning 。 但是创建数千个任务可能是个问题,每个任务都要求新线程。 或者相反,您可能会遇到线程饥饿而未指定它。

考虑它的一个简单方法是:您是否更喜欢在新线程中运行新任务或者您不关心? 如果是 – 然后使用LongRunningOption 。 这并不意味着什么任务将在另一个线程中运行,它只是一个很好的标准,当你必须指定它。

例如,当使用ContinueWith LongRunningExecuteSynchronously相反(有一个检查以防止同时指定)。 如果你有多个continuation,那么也许你想避免队列的开销并在同一个线程中运行特定的延续或相反 – 你不希望其中一个continuation干扰其他的,然后你可以专门使用LongRunning 。 请参阅本文 (和本文 )以了解ExecuteSynchronously

一个长时间运行的任务是一个可能进入等待状态,阻止它运行的线程,或一个占用太多CPU时间的任务(我们将回到这个)。

有些人可能会说这个定义过于宽泛,很多任务都会长时间运行,但想想看,即使等待时间很小,任务仍然没有有效地使用CPU。 如果这些任务的数量增加,你会发现它们没有线性地超过MinWorkerThreads(参见ThreadPool.SetMinThreads ),降级非常糟糕。

它将所有I / O(文件,网络,数据库等)切换为异步的方法。

由于长时间CPU密集型计算,还有长时间运行的任务。

该方法是推迟计算,例如在某些点插入await Task.Yield() ,或者最好通过在另一个之后调度一个任务来显式推迟计算,每个任务处理先前分割的数据块或处理缓冲区直到有限时间限制。

“太多时间”取决于你自己决定。

当您处于共享线程池的环境中时,任何时间都是太多时间,您必须选择合理的值。

例如,在IIS下的ASP.NET中,查看每个请求对最常见请求所花费的平均时间。 类似地,在使用线程池的服务中,例如用于处理消息队列,取每个消息的平均值。

更一般地说,“太多时间”是指工作项目排队的速度快于处理时间。 可能会有突发的工作,因此您应该在对您来说重要的时间单位上进行平均,无论是一秒钟,一分钟,10分钟等等。当您有SLA时,您应该在某处定义此间隔。

在具有合理的价值之后,您必须在实践中看到是否可以增加它或者必须减少它。 更常见的情况是,如果你可以增加它,你最好不要增加它,除非你可以看到显着的性能差异。 “重要”意味着处理项目的数量增加超过线性,因此如果它是线性的(或低于线性,它可能发生),不要这样做。


根据我的经验,如果您通过任何这些定义执行长期任务,通常最好管理自己的线程或线程集。