任务异常长时间处于WaitingToRun状态

Imi*_*ew2 3 c# concurrency task

我有一个程序可以处理并行运行的各种任务。单个任务充当各种管理者,确保在运行下一个任务之前满足某些条件。但是,我发现有时任务会长时间处于WaitingToRun状态。这是下面的代码:

mIsDisposed = false;
mTasks      = new BlockingCollection<TaskWrapper>(new ConcurrentQueue<TaskWrapper>());

Task.Factory.StartNew(() => {
    while (!mIsDisposed) {
         var tTask = mTasks.Take();
         tTask.task.Start();
         while (tTask.task.Status == TaskStatus.WaitingToRun) {
             Console.WriteLine("Waiting to run... {0}", tTask.task.Id);
             Thread.Sleep(200);
         }
         tTask.ready.Wait();
     }
     mTasks.Dispose();
});

DoWork();
DoWork();
DoWork();
DoWork();
DoWorkAsync();
DoWorkAsync();
DoWorkAsync();
DoWorkAsync();
DoWorkAsync();
DoWork();
Run Code Online (Sandbox Code Playgroud)

TaskWrapper非常简单地定义为:

private class TaskWrapper
{
    public Task task  { get; set; }
    public Task ready { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

目前仅在2个位置添加任务:

public void DoWork()
{
    DoWorkAsync().Wait();
}

public Task DoWorkAsync()
{
    ManualResetEvent next = new ManualResetEvent(false);

    Task task  = new Task(() => ActualWork(next));
    Task ready = Task.Factory.StartNew(() => next.Wait());

    mTasks.Add(new TaskWrapper() {
        task  = task,
        ready = ready
    });
    return task;
}
Run Code Online (Sandbox Code Playgroud)

在哪里ActualWork(next)打电话next.Set()

这将使工作排队,并等待直到next设置好后才能继续下一个工作项。您可以等待整个任务完成再通过调用来继续DoWork(),也可以一次将多个任务排队(应该next在设置后运行)。

但是,当通过DoWorkAsync()调用添加任务时,在调用之后tTask.task.Start()tTask.task它处于WaitingToRun状态的时间很短(例如30秒到一分钟),然后神奇地开始运行。我已经使用while循环监视了它,Waiting To Run... #并将显示相当长的时间。

呼叫DoWork()总是立即运行。我确信这与调用Wait设置为运行的任务有关。

我不知所措,在这里。

更新:

我设法使代码正常工作,但是我仍然想知道为什么首先存在问题。

经过一些实验性的更改后,我设法解决了自己的问题,但这更多的是“哦,所以我不能那样做”而不是好的解决方法。事实证明,我的问题是使任务排队太快。通过修改DoWorkAsync()为不再使用Task.Factory.StartNew并更改tTask.ready.Wait()为,tTask.ready.RunSynchronously我设法解决了我的问题。

是否有TaskScheduler延迟我的任务计划的原因?我是否饱和了一些基础资源?这里发生了什么?

Mat*_*son 5

线程将在系统的线程池中运行。线程池始终具有最小数量的可用线程(请参阅ThreadPool.SetMinThreads())。如果您尝试创建的线程数量超过了该数量,则在每个新线程启动之间会引入大约500毫秒的延迟。

线程池中也有最大线程数(请参阅ThreadPool.GetMaxThreads()),如果达到该限制,将不会创建新线程。它会等到旧线程死掉再安排新线程(或者,当然是重新安排旧线程以运行新线程)。

不过,您不太可能达到该限制-可能超过1000。