代码之家  ›  专栏  ›  技术社区  ›  Noel Widmer

在异步操作运行时继续工作流

  •  2
  • Noel Widmer  · 技术社区  · 7 年前

    我已经发表了评论 Eric Lippert's answer What's the difference between Task.Start/Wait and Async/Await?

    我之所以问这个问题,是因为我仍然不确定我是否正确理解了这个概念,以及我将如何实现我的目标。添加大量评论对任何人都没有多大帮助。

    我的理解: await告诉编译器当前线程有能力执行其他一些计算,并在等待的操作完成后返回。这意味着工作流将被中断,直到等待的操作完成。这不会加快包含wait的上下文的计算,但由于更好地使用了 工人 .

    否我的问题: 我想继续工作流程,最后确保操作完成。所以基本上允许 工人 即使等待的操作未完成并在工作流结束时等待完成,也要继续当前工作流。我想要 工人 把时间花在我的工作流程上,而不是跑开去帮助别人。

    我认为可行的方法: 考虑 n async Add 运营和a Flush 处理添加项目的操作。 脸红 需要添加项目。但添加项目并不需要添加上一个项目。所以基本上我想收集所有 跑步 Add 操作,并在添加完所有操作后等待所有操作。在他们被等待之后,他们应该 脸红 预计起飞时间。

    1. 我可以通过添加 添加 任务列表,并最终等待所有这些任务?
    2. 或者,这是伪异步的,最终没有任何好处?
    3. 这和等待所有 添加 直接操作?(没有收集)
    2 回复  |  直到 7 年前
        1
  •  8
  •   Eric Lippert    7 年前

    我的理解:await告诉编译器当前线程有能力执行其他一些计算,并在等待的操作完成后返回。

    这很接近。更好的描述方法是:等待手段 暂停此工作流,直到等待的任务完成 . 如果工作流因任务未完成而挂起,则会释放此线程以查找更多要做的工作,并且工作流将计划在将来任务完成时的某个时间点恢复。等待时选择要执行的操作是给最近调用此工作流的代码的;也就是说 await 实际上是一种幻想 return . 毕竟 回来 意思是“让我的来电者决定下一步要做什么”。

    如果任务在等待点完成,那么工作流将正常继续。

    等待是一个 异步等待 . 它等待任务完成,但在等待的过程中保持忙碌。

    我想继续工作流程,最后确保操作完成。因此,基本上允许工作人员继续当前工作流,即使等待的操作尚未完成,也可以在工作流结束时等待完成。我希望员工花时间在我的工作流程上,而不是跑开去帮助别人。

    当然,没关系。不要等到最后一刻才开始等待任务 需要 工作流继续之前要完成的任务。这是最佳实践。

    但是:如果您的工作流执行的操作需要30毫秒以上的时间,而您处于UI线程上,那么您可能会冻结UI并激怒用户。

    我可以通过将添加任务添加到列表中并最终等待所有这些任务来完成此操作吗?

    你当然可以;这是个好主意。使用 WhenAll combinator轻松等待所有一系列任务。

    是否与直接等待所有添加操作相同?(没有收集)

    不,不一样。正如您正确指出的,等待每个添加操作将确保在前一个添加操作完成之前不会启动任何添加。如果不需要以这种方式序列化这些任务,那么可以通过先启动任务,然后在所有任务都启动后等待它们来创建更高效的工作流。

        2
  •  3
  •   Camilo Terevinto Chase R Lewis    7 年前

    如果我正确理解了您的问题,那么您想要做的是并行化异步工作,这是非常常见的。

    考虑以下代码:

    async Task Add(Item item) { ... }
    
    async Task YourMethod()
    {
        var tasks = new List<Task>();
        foreach (var item in collection)
        {
            tasks.Add(Add(item));
        }
    
        // do any work you need
        Console.WriteLine("Working...");
    
        // then ensure the tasks are done
        await Task.WhenAll(tasks);
    
        // and flush them out
        await Flush();
    }