任务异常长时间处于WaitingToRun状态 [英] Task stays in WaitingToRun state for abnormally long time

查看:110
本文介绍了任务异常长时间处于WaitingToRun状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've got a program that handles a variety of tasks running in parallel. A single task acts as a manager of sorts, making sure certain conditions are met before the next task is ran. However, I've found that sometimes a task will sit in the WaitingToRun state for a very long time. Here's the following code:

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非常简单地定义为:

TaskWrapper is very simply defined as:

private class TaskWrapper
{
    public Task task  { get; set; }
    public Task ready { get; set; }
}

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

And tasks are only currently added in 2 places:

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 之后运行).

This queues work and waits until next has been set before allowing the next work item to proceed. You can either wait for the entire task to finish before continuing by calling DoWork() or queue multiple tasks at once (which are supposed to run after next has been set).

但是,当通过 DoWorkAsync()添加任务时,在调用 tTask.task.Start()之后, tTask.task 位于等待一段时间(例如30秒到一分钟),然后神奇地开始运行.我已经使用while循环对此进行了监视,并且 Waiting To Run ...#将显示一段时间.

However, when adding a task via DoWorkAsync(), after calling tTask.task.Start(), tTask.task sits in the WaitingToRun state for a loooong time (like 30 seconds to a minute), then magically starts running. I've monitored this using the while loop, and Waiting To Run... # will display for quite some time.

调用 DoWork()总是立即运行.我确定这与在要运行的任务上调用 Wait 有关.

Calling DoWork() always runs immediately. I'm sure this has something to do with calling Wait on the task that is set to run.

我不知所措,在这里.

更新:

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

I've managed to make the code work, but I'd still like to know why there's an issue in the first place.

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

After some experimental changes, I've managed to fix my own problem, but it's more of a "Oh, so I just can't do that" rather than a good fix. It turns out my problem was enqueuing tasks to run too quickly. By modifying DoWorkAsync() to no longer use Task.Factory.StartNew and changing tTask.ready.Wait() to tTask.ready.RunSynchronously I've managed to solve my issue.

TaskScheduler 是否有延迟我的任务计划的原因吗?我是否饱和了一些基础资源?这是怎么回事?

Is there a reason the TaskScheduler is delaying the scheduling of my tasks? Am I saturating some underlying resources? What's going on here?

推荐答案

线程将在系统的线程池中运行.线程池始终具有最小数量的可用线程(请参阅

The threads will be run in the system's thread pool. The thread pool has a minimum number of threads available at all times (see ThreadPool.SetMinThreads()). If you try to create more than that many threads, a delay of approximately 500ms will be introduced between each new thread starting.

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

There is also a maximum number of threads in the thread pools (see ThreadPool.GetMaxThreads()), and if you reach that limit no new threads will be created; it will wait until an old thread dies before scheduling a new one (or rather, rescheduling the old one to run your new thread, of course).

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

You are unlikely to be hitting that limit though - it's probably over 1000.

这篇关于任务异常长时间处于WaitingToRun状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆