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

Jer*_*ter 5 c# multithreading task-parallel-library c#-4.0

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

    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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

Ree*_*sey 12

当您不使用该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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*ung 7

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

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