【问题标题】:Immediately process asynchronous results in the order they were requested立即按照请求的顺序处理异步结果
【发布时间】:2019-02-07 22:37:18
【问题描述】:

假设我启动了 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() 按请求的顺序对结果进行排序,而不是按完成的顺序。

不幸的是,这意味着我必须等待所有任务完成才能打印任何内容。

如何在每项任务完成后立即打印结果,但仍遵守请求的顺序?

所以我应该总是看到“1,2,3,4,5” - 但它可能会逐渐到达:

"1"
"1,2,3"
"1,2,3,4"
"1,2,3,4,5"

(不必担心这样做的实际原因,将其视为一个有趣的问题)

【问题讨论】:

标签: c# asynchronous


【解决方案1】:
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);
}

我们首先启动所有任务,然后按顺序循环它们,依次等待每个任务。如果正在等待的任务之前已经完成,则等待只是返回其结果。否则我们等到它完成。

【讨论】:

    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-28
      • 1970-01-01
      • 2016-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多