【问题标题】:Why does ContinueWith execute if I do a delay inside a task如果我在任务中执行延迟,为什么 ContinueWith 会执行
【发布时间】:2013-08-15 20:31:49
【问题描述】:

我对任务并行库中的 ContinueWith 似乎做了什么感到有些困惑。

我的理解是,在任务完成之前不应调用它。如果我处于一个真正的循环中,则根本不应该调用它。

        DateTime t = DateTime.Now.AddSeconds(10);
        Task.Factory.StartNew(async () =>
            {
                while (true)
                {
                    if (t < DateTime.Now)  //after 10s throw
                    { 
                        throw new Exception(); //I expect it to run the continuation here
                    }

                    Console.WriteLine("looped");
                    await Task.Delay(new TimeSpan(0, 0, 1));
                }
            }
        ).ContinueWith(ct => Console.WriteLine("Continued with: {0}",ct.Result.Status)) ;

我希望以下代码在抛出异常之前不会运行 ContinueWith 方法,但事实并非如此。相反,我得到以下输出:

looped
Continued with: WaitingForActivation
looped
looped
looped
looped
looped
looped
looped
looped
looped

为什么当我遇到第一个延迟时它会调用 ContinueWith?

【问题讨论】:

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


    【解决方案1】:

    Task.Factory.StartNew 返回的任务是Task&lt;Task&gt;,因为您的 lambda 返回一个Task,并且该 lambda 在线程池上运行。该 lambda 的结果被包装在 Task&lt;T&gt; 中并放入其 Result 属性中。

    因此您需要致电Unwrap 或更好地使用Task.Run

    【讨论】:

      【解决方案2】:

      你创建了一个邪恶的 async void 代表。

      同步部分完成后,它会立即完成(完成原始Task)。
      无法观察原始委托的异步部分。

      您的原始委托返回一个异步 Task,表示操作的异步部分。
      但是,外部Task 会在同步部分完成后立即完成,您无需等待内部Task 完成。

      相反,您应该调用Task.Run(),它接受Func&lt;Task&gt;
      这样,原始委托的异步部分将有助于原始任务。

      【讨论】:

      • 有没有更好的方法可以让我仍然可以在任务中使用 await?
      • 你为什么在任务中等待?
      • @LukeMcGregor:是的;使用Task.Run()
      • 你也可以直接使用Unwrap
      【解决方案3】:

      ContinueWith 应该在上一次调用返回 Task 的那一刻被调用。 Task 在上一次调用完成之前返回。

      编辑:实际上,SLaks 已经发现了真正的问题。我的陈述仍然正确,尽管在这种情况下不太相关。 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-11
        • 2015-09-14
        • 2018-06-24
        • 2020-07-02
        • 2016-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多