Pet*_*aer 6 c# task-parallel-library
假设我有两个创建Task对象的独立异步函数(我无法控制):
Task A();
Task B();
Run Code Online (Sandbox Code Playgroud)
和其他一些非异步功能
void X();
Run Code Online (Sandbox Code Playgroud)
如何构建一个单独的任务链,按顺序执行所有这些,并允许附加继续(将在X之后执行)?
如果我这样做:
Task Sequential()
{
return A()
.ContinueWith(t => { B(); })
.ContinueWith(t => { X(); });
}
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为B将启动一个新的任务链.如果B需要很长时间才能完成,则首先执行X(以及在返回的Task上,Sequential的调用者可能会继续执行任何其他操作).我需要X作为单个任务链中的最后一个元素,以B任务为先例.
如果我这样做:
Task Sequential()
{
return A()
.ContinueWith(t => { B().ContinueWith(t => { X(); }); });
}
Run Code Online (Sandbox Code Playgroud)
这只能部分解决问题,因为即使A,B和X现在按顺序执行,如果调用者执行Sequential().ContinueWith,该延续将并行执行到B和X,而不是X.
有没有理由不使用等待?例如,
async Task Sequential()
{
await A();
await B();
X();
}
Run Code Online (Sandbox Code Playgroud)
假设您不能按照其他答案中的建议使用(如果可以,您应该),自从.NET 4.0 中async/await引入以来,有一个漂亮的小扩展方法可以满足这种情况: 。它接受 a (或) 并将其“展平”为连续的(或分别),这表示外部任务和内部任务的完成。TaskSystem.Threading.Tasks.TaskExtensions.UnwrapTask<Task>Task<Task<TResult>>TaskTask<TResult>
使用该扩展方法,您的方法可以重写为:
Task Sequential()
{
return A()
.ContinueWith(t => B()).Unwrap()
.ContinueWith(t => X()); // You said X() is "non-async", so no Unwrap here.
}
Run Code Online (Sandbox Code Playgroud)
结果Task将代表整个顺序任务链按预期顺序完成。
还有“子任务”的概念,最初是在任务并行库的早期为此目的而设计的,但它非常难以使用,并且需要您对任务的启动方式有很好的控制,您可以没有。尽管如此,它仍然值得了解(如果只是为了教育)。
| 归档时间: |
|
| 查看次数: |
1370 次 |
| 最近记录: |