我想要按顺序运行两个Task
个对象。目前,我运行它们的代码如下所示:
private async Task Advance(IToken token, SyntaxKind kind)
{
await Approach(token);
await Surpass(token, kind);
}
我的问题是,这是结合它们的最有效方法吗?我知道async
涉及很多状态机逻辑,因此使用ContinueWith
会更有效吗?
private Task Advance(IToken token, SyntaxKind kind)
{
// TODO: This would take advantage of the overload accepting a state
// parameter to avoid the closure allocation
return Approach(token).ContinueWith(() => Surpass(token, kind));
}
如果您认为更有效,请随意指出替代方法(await
和ContinueWith
)。谢谢。
注意:对于我的情况,我正在寻找结合两个非通用(无结果)Task
的最佳方法,但是为了那些通过Google遇到此问题的人可以在答案中包含如何组合两个Task<TResult>
的内容。
答案 0 :(得分:7)
我的问题是,这是结合它们的最有效方法吗?我知道async涉及很多状态机逻辑,所以使用ContinueWith会更有效吗?
状态机逻辑非常简单,在面对任何真正的异步操作(例如,I / O)时都是无关紧要的。确实有一些开销,但这是你为抽象付出的代价。我打赌,除非你在紧密的循环中调用这个方法并且大多数操作同步完成,否则开销不会引人注意(甚至可以测量)。
如果“更高效”,则意味着该方法将以更快的速度运行几纳秒(对CPU更有效),然后是,ContinueWith
比await
更有效。< / p>
如果“更有效”,则表示代码更易于维护(对人类更有效),然后是ContinueWith
is much less efficient than await
。它有same problems that StartNew
does。你自己的例子是这样的例子:它使用当前的TaskScheduer
而不是线程池1,并且没有使用最合适的标志。
如果您想深入了解await
的效果方面,建议您观看Zen of Async并阅读Understanding the Costs of Async and Await。但是,我必须提醒所有读者不要以牺牲可维护代码为代价而陷入微观优化。
答案 1 :(得分:2)
优化执行的方法是指定TaskContinuationOptions.ExecuteSynchronously
。这将导致继续在同一线程上同步执行,导致先行任务转换到其最终状态。因此,您可以避免将延续排队到任务调度程序并将其从工作线程检索到的相关开销。
private Task Advance(IToken token, SyntaxKind kind)
{
// TODO: This would take advantage of the overload accepting a state
// parameter to avoid the closure allocation
return Approach(token).ContinueWith(() => Surpass(token, kind), TaskContinuationOptions.ExecuteSynchronously);
}
如果您对为什么默认情况下没有这样做感到好奇,请参阅Why is TaskContinuationsOptions.ExecuteSynchronously opt-in?