【问题标题】:Waiting for async/await inside a task在任务中等待异步/等待
【发布时间】:2014-09-06 18:33:18
【问题描述】:

我的main() 中有这个构造,它创建了

var tasks = new List<Task>();

var t = Task.Factory.StartNew(
    async () =>
    {
        Foo.Fim();
        await Foo.DoBar();
    });

//DoBar not completed
t.Wait();
//Foo.Fim() done, Foo.DoBar should be but isn't

但是,当我 .Wait 为 t 时,它不会等待对 DoBar() 的调用完成。 如何让它真正等待?

【问题讨论】:

  • 请展示一个简短但完整的程序来说明问题。
  • Stephen Taub wrote a great article 关于如何开始任务。那篇文章中实际上有一个示例,它看起来完全像您的示例(即Task.StartNew(async() =&gt; ...))并解释了正在发生的事情

标签: c# .net task-parallel-library task async-await


【解决方案1】:

不鼓励将Task.Factory.StartNewasync-await 一起使用,您应该改用Task.Run

var t = Task.Run(
    async () =>
    {
        Foo.Fim();
        await Foo.DoBar();
    });

Task.Factory.StartNew api 是在Task-based Asynchronous Pattern (TAP)async-await 之前构建的。它将返回Task&lt;Task&gt;,因为您正在使用恰好是异步的 lambda 表达式启动一个任务,因此返回一个任务。 Unwrap 将提取内部任务,但 Task.Run 会隐含地为您执行此操作。


为了更深入的比较,总有一篇相关的 Stephen Toub 文章:Task.Run vs Task.Factory.StartNew

【讨论】:

  • 有趣,这对Task.Run 来说是一个隐秘的区别。这也回答了我对为什么 Task.Run 与 async/await 不同的困惑。谢谢。
  • 是的,我的理解是不同的默认值是一样的。正如文章所说,相当于"Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);"。当您使用 async/await 而不是简单的操作时,这显然需要进一步阅读。
  • 我今天正在失去理智,试图找出为什么 Factory.Start 会返回 Task
  • 正想问如何使用新工厂传递LongRunning参数,然后发现你写的这篇很棒的博文:blog.i3arnon.com/2015/07/02/task-run-long-running你的回答结合那篇文章真的帮助了我!跨度>
【解决方案2】:

我最近遇到了类似的问题,发现您需要做的就是让 DoBar() 返回一些值并使用 .Result 而不是等待。

var g = Task.Run(() => func(arg));

var val = g.Result;

这将等待 func 返回其输出并将其分配给 val。

【讨论】:

  • -1 因为 OP 不希望返回值,所以 OP 的问题是关于 async/await 纯粹同步的,这似乎是为了调用而返回一次性值结果而不是 Wait()。如果您想以异步方式执行上述操作,您可以使用“var val = await g;”等待任务的结果。如果您不关心结果,那么您可以在任务上简单地 .Wait() - 无需从您的函数返回一次性值并使用 Result 等待。
  • 他的问题是“我如何让它真正等待?”。他在哪里说过返回值?
【解决方案3】:

似乎我通过Unwrap()ing 任务获得了所需的功能。 我不太确定我明白这背后的原因,但我想它有效。

var t = Task.Factory.StartNew(
            async () =>
                {
                        Foo.Fim();
                        await Foo.DoBar();
                }).Unwrap();

编辑:我查找了 Unwrap() 的 ddescription: Creates a proxy Task that represents the asynchronous operation of a Task&lt;Task&lt;T&gt;&gt; 我认为这通常是任务所做的,但如果我需要调用 unwrap 我想这很好。

【讨论】:

  • 是的,另一个答案非常全面。 Task.Run() 似乎是要走的路。
  • 您确定在任务中首先需要Foo.Dim() 吗?即,也许您可​​以简单地这样做:Foo.Fimm(); Foo.DoBar().Wait(); - 无需通过RunStartNew 创建新的Task
  • @Noseratio 公平点。我没有给出上下文来说明为什么需要它(它是),但检查我们是否过度设计东西总是好的。
  • Unwrap() 最终抛出一个Start may not be called on a promise-style task. 异常:/
猜你喜欢
  • 1970-01-01
  • 2014-03-18
  • 1970-01-01
  • 2013-02-10
  • 2017-07-22
  • 1970-01-01
  • 1970-01-01
  • 2016-07-24
  • 2019-04-08
相关资源
最近更新 更多