跳过异步/等待?
我试图了解在某些情况下跳过异步/等待异步或是否会导致陷阱的优化。下面的代码是一个示例,但有助于简化我的问题和理解。
说我有以下代码:
public async Task<string> CreateRandomString()
{
var myTitleTask = GetTitle();
var randomString = CreateRandomString();
var myTitle = await myTitleTask;
return myTitle + randomString;
}
private async Task<string> GetTitle()
{
return await GetTitleFromWebServiceAsync();
}
可以从getTitle()
这样的方法中删除async
/等待
,
public async Task<string> CreateRandomString()
{
var myTitleTask = GetTitle();
var randomString = CreateRandomString();
var myTitle = await myTitleTask;
return myTitle + randomString;
}
private Task<string> GetTitle()
{
return GetTitleFromWebServiceAsync();
}
例如我们将尽可能长时间地延迟到任务
从getTitle()
,从而进行其他工作直到我们等待,还是会引起任何问题?
在第二个示例中,我认为这是更优化和更好的方法,但只想确保我不会陷入任何陷阱。请对此做出想法或评论?
I'm trying to understand if there's an optimisation in skipping async/await in certain situations or whether this could lead to a pitfall. Code below is made up example but it'll help to simplify for my question and understanding.
Say I have the following code:
public async Task<string> CreateRandomString()
{
var myTitleTask = GetTitle();
var randomString = CreateRandomString();
var myTitle = await myTitleTask;
return myTitle + randomString;
}
private async Task<string> GetTitle()
{
return await GetTitleFromWebServiceAsync();
}
It's possible to remove the async
/await
from the GetTitle()
method like this:
public async Task<string> CreateRandomString()
{
var myTitleTask = GetTitle();
var randomString = CreateRandomString();
var myTitle = await myTitleTask;
return myTitle + randomString;
}
private Task<string> GetTitle()
{
return GetTitleFromWebServiceAsync();
}
Does this optimise anything because we are delaying as long as possible to await the Task
from GetTitle()
and thus doing other work until we await or does this cause any problems?
In the second example I thought this was more optimise and better approach but just want to make sure I'm not falling into any pitfall. Thoughts or comments on this please?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,我不会进入基准测试,但这是我有时会做的。如果我需要“扫描”图像或某些文件的文件夹。我以目录循环的范围启动任务,然后通过它们枚举以获取相关文件,退出循环并等待所有文件,即并行浏览每个文件夹。而不是
task t = task.run(()=&gt; foo());
我们始终可以按照您的建议做,只需返回任务而不是等待它,然后在末尾>等待myTask
或等待mytasks
也有其他用途,例如MicroServices Architecture,您可能想“ fire and Insplo of of fire and忘记”创建的订单,例如电子邮件服务,通知服务等...处理所有这些,然后将成功返回给用户。就像您在亚马逊上下订单一样,您只能感谢您下订单。对于像您这样的顺序函数,我看不到在第三行或第五行上等待它的好处。这确实取决于代码。
Well, I'm not going to go into benchmarks but this is what I sometimes do. If I need to "scan" a folder for images or some files. I start tasks in a foreach loop of directories and enumerate through them to get the relevant files, exiting the loop and await them all i.e. look through each folder in parallel. Instead of
Task t = Task.Run(() => foo());
we can always do as you suggested, simply return the task instead of awaiting it and then in the endawait myTask
orawait myTasks
There are also other uses like in a microservices architecture, you might want to "fire and forget" about an order created, such that email service, notification service, etc... handle all that and you return success to the user. Pretty much just like you place an order on Amazon and you only get a thank you for placing the order. For a sequential function like yours, I don't see a benefit of awaiting it on the 3rd line or the 5th line. It really depends on the code.
当您用一种方法进行一次调用时,可以肯定地省略异步+等待。
当方法中有多个语句时,事情可能会出错。
来自Stephen Cleary的 nofollow noreferrer“
本文还显示了当涉及例外和更细微的异步案例时的问题,并且例外部件与您的示例有关(因为您执行
任务t = ...;其他代码;其他代码;等待T;
) :When you do a single call in a method it's safe to omit async+await.
When there are multiple statements in the method things can go wrong.
From Stephen Cleary's Eliding Async and Await:
The article also shows issues when exceptions are involved and a more nuanced case of AsyncLocal and the exceptions part is relevant to your example (because you do
Task t = ... ; other code; await t;
):是的,这样做是完全安全的。
它们是直接等效的,跳过异步/等待的效率应该更高,但我希望差异很小。如果您对实际数字感兴趣,我建议您进行一些基准测试。
Yes, and it is perfectly safe to do so.
They are directly equivalent, skipping a async/await should be slightly more efficient, but I would expect the difference to be minimal. I would recommend doing some benchmarking if you are interested in actual numbers.
是的,当您发现自己仅在返回语句中使用等待时,从方法签名中删除异步关键字会优化性能和捆绑尺寸。
C#编译器将用异步标记的每种方法转换为继承IASYNCSTATEMACHINE的单独类!
它基本上将异步方法分为几个同步部分(2个等待= 3个部分),并根据类状态执行每个部分。
因此,将方法修改为类后,将100个字节的开销添加到您的最终捆绑包大小(如今通常是一个很小的问题)。
而且,当存在等待关键字时,运行时的性能开销必须切换线程。因此,返回任务而无需等待任务将导致上下文切换较少,这非常昂贵。
Yes, when you find yourself only using await in the return statement, removing the async keyword from the method signature optimizes performance and bundle size.
The C# compiler turns each method marked with async to a separate class that inherits IAsyncStateMachine!
It basically divides the async method into several synchronous portions(2 awaits = 3 portions) and executes each portion depending on the class state.
Thus, having modified the method to a class, an overhead of 100 bytes is added to your final bundle size(usually a very minor problem nowadays).
And there is also the performance overhead of the runtime having to switch threads when the await keyword is present. So returning the task without awaiting it when possible will result in less context-switching, which is quite expensive.