如果我在任务中做了延迟,为什么ContinueWith会执行

时间:2013-08-15 20:31:50

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

我对任务并行库中的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?

3 个答案:

答案 0 :(得分:6)

Task.Factory.StartNew返回的任务是Task<Task>,因为您的lambda返回Task并且该lambda在线程池上运行。该lambda的结果包含在Task<T>中并放入其Result属性。

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

答案 1 :(得分:4)

你创建了一个邪恶的async void委托。

一旦同步部件完成,它就会完成(完成原始Task)。
无法观察原始委托的异步部分。

您的原始委托会返回异步Task,表示操作的异步部分 但是,只要同步部分完成,外部Task就会完成,您永远不会等待内部Task完成。

相反,您应该致电Task.Run(),接受Func<Task> 这样,原始委托的异步部分将对原始任务做出贡献。

答案 2 :(得分:0)

在前一次调用返回ContinueWith时,应调用

Task。在完成之前,Task将从上一个呼叫返回。

编辑:实际上,SLaks确定了真正的问题。我的陈述仍然是正确的,虽然在这种情况下不太相关。 :)