Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 等待/异步vs.“;经典;异步(回调)_C#_Asynchronous_Async Ctp_C# 5.0 - Fatal编程技术网

C# 等待/异步vs.“;经典;异步(回调)

C# 等待/异步vs.“;经典;异步(回调),c#,asynchronous,async-ctp,c#-5.0,C#,Asynchronous,Async Ctp,C# 5.0,因此,新的异步CTP非常酷;它使我的生活更加轻松,不必编写命名回调方法,并且使方法的意图更加清晰 现在我已经开始使用它了,我想知道async/await和“经典”异步回调语法之间可能有什么区别 这里有几个我想问的问题,但还有很多其他问题我现在没有想到,以后可能也会想到 其中一个可能提供比另一个更好的性能吗 其中一个的开销是否大于另一个 在高性能环境中使用哪个更好 与匿名函数和迭代器一样,async和await关键字也是语法上的糖分。从技术意义上讲,它们的效率并不比同等的非含糖版本高或低。它们只

因此,新的异步CTP非常酷;它使我的生活更加轻松,不必编写命名回调方法,并且使方法的意图更加清晰

现在我已经开始使用它了,我想知道async/await和“经典”异步回调语法之间可能有什么区别

这里有几个我想问的问题,但还有很多其他问题我现在没有想到,以后可能也会想到

  • 其中一个可能提供比另一个更好的性能吗
  • 其中一个的开销是否大于另一个
  • 在高性能环境中使用哪个更好

与匿名函数和迭代器一样,
async
await
关键字也是语法上的糖分。从技术意义上讲,它们的效率并不比同等的非含糖版本高或低。它们只会为您节省大量的键入工作。

答案很复杂,当前的wait编译器实现在几个方面都比回调好,但在某些情况下更糟

.NET执行上下文:我们打算通过(…)捕获和还原.NET执行上下文来等待和继续。否则它将无法通过.NET安全要求,因为这样您就可以获取任意内容,如凭据等,并将它们保留在线程池中以供下一个工作项使用。对于'await',这是我们在内部构建中所做的调整,但这是在我们制作了//BUILD developer预览之后

内存分配:在几个方面,“等待”在内存分配上比手动回调更好。关键是,对于具有许多等待的函数,您真正生成的是相当于几个回调的函数。如果在线性执行顺序中有5次等待,并且执行始终流向末尾,那么等价的操作将需要5次回调。对于这5个回调中的每一个,都可以生成一个单独的lambda闭包对象和一个表示特定lambda的委托。在“await”情况下,编译器知道您不会将委托对象用于其他任何事情。因此,整个方法共享一个闭包和一个委托,并使用一个内部状态机跟踪您在方法中的位置。因此,在这种情况下,“await”分配的对象更少,这实际上可以加快程序的速度,因为太多的对象=GC必须花费更多的时间来找出哪些对象是活的/死的

短切“wait”的语义也比回调更奇特。在创建回调lambda的情况下,无论发生什么情况,编译器都必须分配闭包和lambda的入口点委托。对于“await”,await契约允许为已经“完成”的等待项提供更优化的代码路径。如果waitible在waiting得到评估之前就说它“完成了”,那么语义仅仅是一个拉出结果的简单过程。这意味着编译器有机会延迟分配直到您真正需要它,因此您永远不会支付闭包分配、委托分配或调度成本,除非您确实需要它。当前的开发人员预览编译器包括这些性能优化

以风险换取性能如果您真的想绕过.NET安全模型,您可以想象这样一种情况:如果您绝对相信永远不需要捕获/恢复上下文,您可以通过避免执行上下文包/恢复来获得一点性能。然而,大多数.NET的方法都会在幕后默默地完成这项工作,因此您确实需要知道哪些方法会在没有它的情况下为您提供原始访问。NET的经验法则是,如果API在部分信任中可用(例如Silverlight),那么API肯定会在调用时捕获上下文,然后恢复上下文,如果它是一个在别处传输执行的API(例如ContinueWith、QueueUserWorkItem(…),等等)。如果您使用自己的线程池,只对代理进行排队,您可以绕过它,但很可能不需要它


我的个人推荐使用等待。这是更高的层次,这是你想要的。我们已经投入了相当多的努力来调整它以适应这个版本,我们可能会进一步调整它。基于回调的API将受到更大的限制,因为编译器在开始打破语言规则之前只能进行如此多的调优。方法中的等待允许您使用比回调更智能的闭包。而且。。。wait的读取/使用要比回调直观得多:)

哪种经典异步模型?有三个不同的链接。@SLaks链接已断开。我知道6年过去了,但是你有更新过的链接吗?嗯,它们传播了同步上下文(AFAIK),如果你传递了很多不需要在原始线程中运行的延续,这可能会使它们稍微慢一点。不使用
wait
也可以做到这一点,但这不是
ContinueWith
中的默认设置。管理同步和尝试/捕获状态只是其中的一部分。Aaronaught:我认为您正在考虑ConfigureWait(…),它实际上不允许您禁用/启用同步传播。ConfigureAwait(…)允许您决定是否要使用同步上下文进行调度。正在进行的设计(尚未发布)将确保当一个方法由于等待而打包/还原时,.NET执行上下文将始终打包/解包。@TheoYaung:我想的是,如果您希望回调使用
System.Threading.Tasks
,在原始线程中运行,然后,您需要将
TaskScheduler.FromCurrentSynchronizationContext
作为参数传递给
ContinueWith
,而使用
构建的异步序列等待