7

バックグラウンド タスクをブロッキング コレクション (バックグラウンドで追加) に追加しています。

GetConsumingEnumerable によって返された Enumerable で Task.WhenAll を使用して待機しています。

私の質問は: IEnumerable を受け取る Task.WhenAll のオーバーロードは、潜在的に無限の量のタスクを受け取るために「準備」されていますか?

このようにできるのか、それともこのように使用することを意図していたのか、よくわかりません。

private async Task RunAsync(TimeSpan delay, CancellationToken cancellationToken)
{
    using (BlockingCollection<Task> jobcollection = new BlockingCollection<Task>())
    {
        Task addingTask = Task.Run(async () =>
        {
            while (true)
            {
                DateTime utcNow = DateTime.UtcNow;
                var jobs = Repository.GetAllJobs();
                foreach (var job in GetRootJobsDue(jobs, utcNow))
                {
                    jobcollection.Add(Task.Run(() => RunJob(job, jobs, cancellationToken, utcNow), cancellationToken), cancellationToken);
                }

                await Task.Delay(delay, cancellationToken);
            }
        }, cancellationToken);

        await Task.WhenAll(jobcollection.GetConsumingEnumerable(cancellationToken));
    }
}
4

3 に答える 3

7

キャンセル トークンがキャンセルされるまで待つだけなので、そうする必要があります。他の人が説明した理由によりWhenAll、タスクの無限のシーケンスで使用することは、それを行う方法ではありません。決して完了しないタスクを取得する簡単な方法があります。

await new TaskCompletionSource<bool>().Task
    .ContinueWith(t => { }, cancellationToken);
于 2014-08-25T15:03:29.013 に答える
5

Task.WhenAll無限の数のタスクでは機能しません。最初に (同期的に) enumerable が終了するのを待ち、次に (非同期的に) それらがすべて完了するのを待ちます。

非同期でシーケンスに反応したい場合は、IObservable<Task>(Reactive Extensions) を使用する必要があります。TPL データフローBufferBlockは、同期コードまたは非同期コードのいずれかで動作する「キュー」として使用でき、簡単に に変換できIObservable<Task>ます。

于 2014-08-25T14:58:49.463 に答える
0

コレクションを列挙しようとすることを想定してTask.WhenAllいます。つまり、コレクションが完了するかキャンセルされるまで、それ自体がブロックされます。そうでない場合、理論的awaitには、タスクが作成される前にコードが終了する可能性があります。そのため、余分なブロックが存在することになります...スレッドが作成されるのを待ってブロックし、タスクが完了するまで再びブロックします。同じ時点までブロックされるため、コードにとって悪いことではないと思います。

于 2014-08-25T14:58:36.793 に答える