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不适用于无限数量的任务。它将首先(同步)等待可枚举完成,然后(异步)等待它们全部完成。

如果您想以异步方式对序列做出反应,那么您需要使用IObservable<Task>(Reactive Extensions)。您可以将 TPL 数据流BufferBlock用作可以使用同步或异步代码的“队列”,并且可以轻松转换为IObservable<Task>.

于 2014-08-25T14:58:49.463 回答
0

我假设Task.WhenAll它将尝试枚举集合,这意味着它本身将阻塞,直到集合完成或取消。如果没有,那么理论上代码可以await在创建任务之前完成。所以那里会有一个额外的块......它将阻塞等待线程被创建,然后再次阻塞直到任务完成。我认为这对您的代码来说不是一件坏事,因为它仍然会阻塞直到同一时间点。

于 2014-08-25T14:58:36.793 回答