And*_*lon 1 c# concurrency async-await
async-await功能使编写非阻塞代码变得优雅.但是,在非阻塞的情况下,在异步函数中执行的工作仍然可以是非平凡的.
在编写异步代码时,我发现编写遵循"一直沿着兔子洞"的模式的代码是很自然的,可以这么说,调用树中的所有方法都标记为异步,并且使用的API是异步的; 但即使在非阻塞的情况下,执行的代码也会占用相当多的上下文线程的时间.
您是如何以及何时在异步上同时运行异步方法的?如果在调用树中创建了更高或更低的新任务,是否应该错误?这种"优化"是否有最佳实践?
我已经async在生产中使用了几年.我推荐一些核心"最佳实践":
async代码.使用async"一直向下".(推论:除非你必须使用async Task,async void否则更喜欢).async voidConfigureAwait(false)尽可能在您的"库"的方法.你已经找到了" async一直向下"的部分,而你正处于ConfigureAwait(false)有用的地步.
假设你有一个async方法A调用另一个async方法B.A使用结果更新UI B,但B不依赖于UI.所以我们有:
async Task A()
{
var result = await B();
myUIElement.Text = result;
}
async Task<string> B()
{
var rawString = await SomeOtherStuff();
var result = DoProcessingOnRawString(rawString);
return result;
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我会调用B一个"库"方法,因为它实际上不需要在UI上下文中运行.现在,B 确实在UI线程中运行,因此DoProcessingOnRawString导致响应问题.
所以,ConfigureAwait(false)在每个await中添加一个B:
async Task<string> B()
{
var rawString = await SomeOtherStuff().ConfigureAwait(false);
var result = DoProcessingOnRawString(rawString);
return result;
}
Run Code Online (Sandbox Code Playgroud)
现在,当B恢复后,await荷兰国际集团SomeOtherStuff(假设它实际上确实有await),它将恢复对线程池线程,而不是UI上下文.当B完成后,即使它的线程池运行时,A将恢复在UI方面.
您无法添加ConfigureAwait(false),A因为A取决于UI上下文.
您还可以选择将任务显式排队到线程池(await Task.Run(..)),如果您具有特定的CPU密集型功能,则应该执行此操作.但是如果你的表现遭受"成千上万的剪纸",你可以ConfigureAwait(false)用来将大量的async"管家" 卸载到线程池中.
您可能会发现我的介绍帖子很有帮助(它更多地涉及"为什么"),而asyncFAQ也有很多很棒的参考资料.
| 归档时间: |
|
| 查看次数: |
817 次 |
| 最近记录: |