.Continue 在任务完成前开始
Posted
技术标签:
【中文标题】.Continue 在任务完成前开始【英文标题】:.Continue starts before task is completed 【发布时间】:2012-10-28 10:47:13 【问题描述】:我在 C#、VS2012、WPF 4.5 中有以下代码。
我的期望是,.ContinueWith
将在任务完全完成后执行(这是延续的全部目的,不是吗?)。
这应该导致finalResult
中的值为 2。
int myTestInt = 0;
Task task = Task.Factory.StartNew(async () =>
myTestInt = 1;
await Task.Delay(TimeSpan.FromSeconds(6));
myTestInt = 2;
).ContinueWith(_ =>
int finalResult = myTestInt;
);
事实上,finalResult
被赋值为 1。所以看起来延续已经在await
语句上开始了。
这是预期的行为吗?我在这里错过了什么吗?我不能依靠ContinueWith
在任务完成后开始吗?
更新:
贾斯汀的回答启发了我检查以下内容:
int myTestInt = 0;
Task task=Task.Factory.StartNew(async () =>
myTestInt = 1;
await Task.Delay(TimeSpan.FromSeconds(6));
myTestInt = 2;
);
task.Wait();
int result2 = myTestInt;
finalResult 仍然设置为 1。有没有办法可靠地等待包含 await
s 的任务完成?
【问题讨论】:
我认为你应该直接调用Task.Delay
——而不是使用await
关键字。
你会注意到_
实际上是一个Task<Task>
,完全支持Justin所说的......
其实使用Task.Delay(6)会产生预期的结果,但不会等待6秒。我认为删除整行几乎是一样的。
【参考方案1】:
当您将 async
委托传递给 Task.Factory.StartNew
时,返回的 Task
仅代表该委托的第一部分(直到它 await
s 尚未完成的内容)。
但是,如果您将 async
委托传递给新的 Task.Run
方法(为此包含该方法),则返回的 Task
代表整个委托。因此,您可以按预期使用ContinueWith
。 (虽然await
通常比ContinueWith
更好)。
有关StartNew
与Run
的更多信息,请参阅Stephen Toub's post on the topic。
【讨论】:
【参考方案2】:await 将立即将控制权返回给调用函数,在本例中是您的任务的 StartNew。这意味着任务将完成并执行 ContinueWith。 如果您确实希望在 ContinueWith 之前完成任务,则不要等待 Task.Delay。
【讨论】:
我认为你是对的 - await 将当前任务标记为已完成。虽然不是(至少从语义的角度来看不是)。由于 await 是当今所有软件的基本构建块,这意味着永远不要再依赖 ContinueWith。你不认为这是一个错误吗?【参考方案3】:我在 MSDN 中看到了这个::-)
public async void button1_Click(object sender, EventArgs e)
pictureBox1.Image = await Task.Run(async() =>
using(Bitmap bmp1 = await DownloadFirstImageAsync())
using(Bitmap bmp2 = await DownloadSecondImageAsync())
return Mashup(bmp1, bmp2);
);
所以不要忘记 "async()" !!!
【讨论】:
他的代码有async
他的问题是他正在使用TaskFactory
,它没有接受Func<Task>
或Func<Task<T>>
的重载,而Task.Run
确实有。
以上是关于.Continue 在任务完成前开始的主要内容,如果未能解决你的问题,请参考以下文章
如何再 freemarker中 的list 循环中 实现 continue的功能?