【发布时间】:2024-01-22 18:06:01
【问题描述】:
我有一个程序可以处理并行运行的各种任务。单个任务充当各种管理器,确保在运行下一个任务之前满足某些条件。但是,我发现有时某个任务会长时间处于 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;
}
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 延迟我的任务安排是否有原因?我是否饱和了一些基础资源?这是怎么回事?
【问题讨论】:
标签: c# concurrency task