我有一个程序可以处理并行运行的各种任务。单个任务充当各种管理器,确保在运行下一个任务之前满足某些条件。但是,我发现有时任务会处于 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();
TaskWrapper 的定义非常简单:
private class TaskWrapper
{
public Task task { get; set; }
public Task ready { get; set; }
}
目前仅在 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;
}
Where ActualWork(next)
calls next.Set()
.
这会将工作排队并等待,直到next
在允许下一个工作项目继续进行之前已设置。您可以等待整个任务完成,然后再继续调用DoWork()
或一次对多个任务进行排队(这些任务应该在next
已经设置好了)。
但是,当通过以下方式添加任务时DoWorkAsync()
,调用后tTask.task.Start()
, tTask.task
处于 WaitingToRun 状态很长一段时间(例如 30 秒到一分钟),然后神奇地开始运行。我已经使用 while 循环对此进行了监控,并且Waiting To Run... #
将显示相当长一段时间。
Calling DoWork()
总是立即运行。我确信这与调用有关Wait
在设置为运行的任务上。
我在这里不知所措。
UPDATE:
我已经设法使代码正常工作,但我仍然想知道为什么会出现问题。
经过一些实验性的改变后,我成功地解决了自己的问题,但这更多的是“哦,所以我不能这样做”,而不是一个好的解决方案。事实证明我的问题是排队任务运行得太快。通过修改DoWorkAsync()
不再使用Task.Factory.StartNew
和改变tTask.ready.Wait()
to tTask.ready.RunSynchronously
我已经成功解决了我的问题。
有什么原因吗TaskScheduler
是否推迟了我的任务安排?我是否已经饱和了某些基础资源?这里发生了什么?