C# 任务处于等待或运行状态的时间异常长
我有一个程序,可以处理并行运行的各种任务。单个任务充当排序管理器,确保在运行下一个任务之前满足某些条件。然而,我发现有时任务会在等待或运行状态下等待很长时间。以下是代码:C# 任务处于等待或运行状态的时间异常长,c#,concurrency,task,C#,Concurrency,Task,我有一个程序,可以处理并行运行的各种任务。单个任务充当排序管理器,确保在运行下一个任务之前满足某些条件。然而,我发现有时任务会在等待或运行状态下等待很长时间。以下是代码: mIsDisposed = false; mTasks = new BlockingCollection<TaskWrapper>(new ConcurrentQueue<TaskWrapper>()); Task.Factory.StartNew(() => { while
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();
和任务当前仅在两个位置添加:
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
之后运行)
但是,当通过doworksync()
添加任务时,在调用tTask.task.Start()
后,tTask.task
处于WaitingToRun状态一段时间(如30秒到一分钟),然后神奇地开始运行。我已经使用while循环监视了这个,并且正在等待运行#代码>将显示一段时间
调用DoWork()
总是立即运行。我确信这与对设置为运行的任务调用Wait
有关
在这里,我不知所措
更新:
我已经设法使代码正常工作,但我仍然想知道为什么首先会出现问题
经过一些实验性的改变后,我成功地解决了自己的问题,但这更像是一个“哦,所以我做不到”而不是一个好的解决方案。原来我的问题是让任务排队运行得太快。通过修改doworksync()
以不再使用Task.Factory.StartNew
并将tTask.ready.Wait()
更改为tTask.ready.RunSynchronously
我已经设法解决了我的问题
TaskScheduler
延迟我的任务调度有什么原因吗?我是否占用了一些基础资源?这里发生了什么?线程将在系统的线程池中运行。线程池始终具有最小可用线程数(请参阅)。如果您尝试创建的线程数量超过该数量,则在每个新线程启动之间将引入大约500毫秒的延迟
线程池中还有一个最大线程数(请参阅),如果达到该限制,将不会创建新线程;在调度新线程之前,它将一直等到旧线程死亡(或者更确切地说,重新调度旧线程以运行新线程)
不过,你不太可能达到这个极限——它可能超过1000英镑。刚刚遇到了类似的问题
我有一堆类似的任务在fite循环中运行,其中一个任务经常处于WaitingToRun状态
以这种方式创建任务为我带来了好处:
_task = new Task(() => DoSmth(_cancellationTokenSource.Token), TaskCreationOptions.LongRunning);
_task.Start();
好的,我刚刚遇到了一个类似的问题。一些创建并启动任务的代码已经运行,但任务从未启动(它只是将状态更改为WaitingToRun)
在这个线程中尝试了其他选项但没有效果后,我仔细考虑了一下,并意识到调用此方法的代码本身是在一个延续任务中调用的,该任务已指定在UI任务调度器上运行(因为它需要更新UI)
大概是
void Main()
{
var t1 = new Task(() => Console.WriteLine("hello, I'm task t1"));
t1.ContinueWith(t => CreateAndRunASubTask(), TaskScheduler.FromCurrentSynchronizationContext());
t1.Start();
Console.WriteLine("All tasks done with");
}
// Define other methods and classes here
public void CreateAndRunASubTask()
{
var tsk = new Task(() => Console.WriteLine("hello, I'm the sub-task"));
tsk.Start();
Console.WriteLine("sub-task has been told to start");
tsk.Wait();
// the code blocks on tsk.Wait() indefinately, the tsk status being "WaitingToRun"
Console.WriteLine("sub-task has finished");
}
修复非常简单-在指定延续任务时,需要指定TaskContinuationOption:TaskContinuationOptions.HidesScheduler
这有。。。(摘自XML注释)
指定由continuation通过调用方法创建的任务
例如System.Threading.Tasks.Task.Run(System.Action)或
System.Threading.Tasks.Task.ContinueWith(System.Action{System.Threading.Tasks.Task})
查看默认的调度程序(System.Threading.Tasks.TaskScheduler.default),而不是
而不是作为当前计划程序运行此延续的计划程序
ie(在我的例子中)
希望这有助于别人,因为它让我难堪了好一阵子 就这样!奇怪的是,它们延迟了新线程的启动。我认为这是为了使您的程序不会无意中试图扼杀系统上的其他进程。。。但是伊恩诺。
void Main()
{
var t1 = new Task(() => Console.WriteLine("hello, I'm task t1"));
t1.ContinueWith(t => CreateAndRunASubTask(), TaskScheduler.FromCurrentSynchronizationContext());
t1.Start();
Console.WriteLine("All tasks done with");
}
// Define other methods and classes here
public void CreateAndRunASubTask()
{
var tsk = new Task(() => Console.WriteLine("hello, I'm the sub-task"));
tsk.Start();
Console.WriteLine("sub-task has been told to start");
tsk.Wait();
// the code blocks on tsk.Wait() indefinately, the tsk status being "WaitingToRun"
Console.WriteLine("sub-task has finished");
}
t1.ContinueWith(t =>
CreateAndRunASubTask(),
System.Threading.CancellationToken.None,
TaskContinuationOptions.HideScheduler,
TaskScheduler.FromCurrentSynchronizationContext());