当我不使用TaskCreationOptions.LongRunning时出现奇怪的行为

我有一个具有任意数量轮询器的引擎,每个轮询器每隔几秒就进行一次“轮询”。 我希望轮询器在不同的线程中运行,但是单个轮询器中的每个“轮询”应该是顺序的,以便在下一个轮询器之后发生。 一切正在使用此代码启动轮询过程:

public void StartPolling() { Stopwatch watch = new Stopwatch(); while (Engine.IsRunning) { Task task = Task.Factory.StartNew(() =>{ watch.Restart(); Poll(); watch.Stop(); },TaskCreationOptions.LongRunning); task.Wait(); if(Frequency > watch.Elapsed) Thread.Sleep(Frequency - watch.Elapsed); } } 

然而,我花了一段时间才发现TaskCreationOptions.LongRunning选项,它解决了我遇到的一个奇怪的问题,我仍然不明白。 没有这个选项,如果我运行一个创建1-3个这些轮询器的测试,一切正常。 如果我创造了4+,那么我遇到了奇怪的行为。 其中三个轮询器可以工作,一个只执行一个轮询,剩下的任何轮询都不会轮询。 总的来说,我的任务是长期运行的。 毕竟他们正在运行我的整个程序。 但我不明白为什么没有这个选项设置我会得到一些不好的行为。 任何帮助,将不胜感激。

当您不使用LongRunning标志时,任务将在线程LongRunning线程上调度,而不是在其自己的(专用)线程上。 这可能是您行为改变的原因 – 当您在没有LongRunning标志的情况下运行时,由于您的进程中的其他线程,您可能会遇到线程LongRunning饥饿。

话虽这么说,你上面的代码并没有多大意义。 你正在启动一个专用线程(通过Task … StartNew with LongRunning)来启动任务,然后立即调用task.Wait()来阻止当前线程。 在当前线程中按顺序执行此操作会更好:

 public void StartPolling() { Stopwatch watch = new Stopwatch(); while (Engine.IsRunning) { watch.Restart(); Poll(); watch.Stop(); if(Frequency > watch.Elapsed) Thread.Sleep(Frequency - watch.Elapsed); } } 

TPL(和传统的ThreadPool)限制池中的线程数(通常是CPU核心数量的一小部分,通常是2x核心)。 如果将任务标记为LongRunning ,则它知道该任务不会很快完成,并且可能不会将此任务置于线程限制LongRunning

如果没有LongRunning ,它会假定您的任务将快速完成(它没有完成),因此它保持在线程限制内。 然后,如果您创建的任务多于线程限制并且正在运行的任务永远不会结束,则TPL会阻止所有其他任务运行等待那些正在运行的任务完成(这是他们永远不会做的)。