假设我启动了5个异步任务,并且我想按请求的顺序打印结果:
public async void RunTasks()
{
var tasks = new List<Task<int>>();
for(int i=1; i<=5; i++)
{
tasks.Add(DoSomething(i));
}
var results = await Task.WhenAll(tasks);
Console.WriteLine(String.Join(',', results));
}
public async Task<int> DoSomething(int taskNumber)
{
var random = new Random();
await Task.Delay(random.Next(5000));
return taskNumber;
}
这将始终打印“ 1、2、3、4、5”-因为Task.WhenAll()按照请求的的顺序而不是按照它们完成的顺序对结果进行排序。 / p>
不幸的是,这意味着我必须等待所有任务完成才能打印任何内容。
如何在完成每个任务后立即打印每个任务的结果,但仍然尊重请求的顺序?
所以我应该始终看到“ 1,2,3,4,5”-但它可能会逐渐出现:
"1"
"1,2,3"
"1,2,3,4"
"1,2,3,4,5"
(无需担心这样做的实际原因,将其视为一个有趣的问题)
答案 0 :(得分:3)
var tasks = new List<Task<int>>();
for(int i=1; i<=5; i++)
{
tasks.Add(DoSomething(i));
}
foreach (var task in tasks)
{
var result = await task;
Console.WriteLine(result);
}
我们首先启动所有任务,然后依次循环执行它们,依次等待每个任务。如果正在等待的任务先前已经完成,则等待仅返回其结果。否则,我们等待直到完成。
答案 1 :(得分:2)
尝试TransformBlock
,即使元素是并行处理的,它也会按照默认接收的顺序逐个输出处理的项目。
public async Task Order()
{
var tBlock = new TransformBlock<int, string>(async x =>
{
await Task.Delay(100);
return x.ToString();
}, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = 10 });
var sub = tBlock.AsObservable().Subscribe(x => Console.Write(x));
foreach (var num in Enumerable.Range(0, 10))
{
tBlock.Post(num);
}
tBlock.Complete();
await tBlock.Completion;
sub.Dispose();
}
输出:
0123456789