並行して実行されるさまざまなタスクを処理するプログラムがあります。単一のタスクが一種のマネージャーとして機能し、次のタスクが実行される前に特定の条件が満たされていることを確認します。ただし、タスクが非常に長い間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秒から1分など)待機し、魔法のように実行を開始します。whileループを使用してこれを監視しましたがWaiting To Run... #
、かなり長い間表示されます。
呼び出しDoWork()
は常にすぐに実行されます。Wait
これは、実行するように設定されているタスクの呼び出しと関係があると確信しています。
ここで途方に暮れています。
アップデート:
私はなんとかコードを機能させることができましたが、そもそもなぜ問題があるのか知りたいのです。
いくつかの実験的な変更の後、私は自分の問題をなんとか修正することができましたが、それは良い修正というよりはむしろ「ああ、それで私はそれをすることができない」ということです。私の問題は、タスクの実行が速すぎることでした。DoWorkAsync()
使用しないように変更し、にTask.Factory.StartNew
変更することで、問題を解決することができました。tTask.ready.Wait()
tTask.ready.RunSynchronously
TaskScheduler
タスクのスケジュールが遅れている理由はありますか?いくつかの基礎となるリソースを飽和させていますか?何が起きてる?