我对任务并行库中的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?
答案 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确定了真正的问题。我的陈述仍然是正确的,虽然在这种情况下不太相关。 :)