代码之家  ›  专栏  ›  技术社区  ›  FBryant87

立即按请求的顺序处理异步结果

  •  0
  • FBryant87  · 技术社区  · 7 年前

    假设我启动了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"
    

    (不必担心做这个的实际推理,把它当作一个有趣的问题来对待)

    2 回复  |  直到 7 年前
        1
  •  3
  •   canton7    7 年前
    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
  •  2
  •   JSteward    7 年前

    试一试 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