任务的使用.由BlockingCollection生成的无限任务
本文关键字:任务 无限 BlockingCollection | 更新日期: 2023-09-27 18:19:24
我正在将后台任务添加到阻塞集合(在后台添加)。
我正在等待任务。GetConsumingEnumerable返回的Enumerable的WhenAll
我的问题是:是任务的过载。当所有接收到一个IEnumerable的"准备好"可能接收无穷无尽的任务时?
我只是不确定我是否可以这样做,或者它是否应该这样使用?
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));
}
}
由于您的目标仅仅是等待取消令牌被取消,因此您应该执行。由于其他人已经解释过的原因,在无限的任务序列上使用WhenAll
并不是解决问题的方法。有更简单的方法来完成一个永远不会完成的任务。
await new TaskCompletionSource<bool>().Task
.ContinueWith(t => { }, cancellationToken);
Task.WhenAll
不能处理无限数量的任务。它将首先(同步)等待可枚举对象完成,然后(异步)等待它们全部完成。
如果你想以异步方式对序列做出反应,那么你需要使用IObservable<Task>
(Reactive Extensions)。您可以使用TPL数据流BufferBlock
作为可以使用同步或异步代码的"队列",并且很容易转换为IObservable<Task>
。
我假设Task.WhenAll
将尝试枚举集合,这意味着它本身将阻塞,直到集合完成或取消。如果没有,那么代码理论上可以在创建任务之前完成await
。所以这里会有一个额外的块。它将阻塞等待线程被创建,然后再次阻塞,直到任务完成。我不认为这对你的代码是件坏事,因为它仍然会阻塞,直到相同的时间点