C# 等待一个无效的异步方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13636648/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Wait for a void async method
提问by MBZ
How can I wait for a void asyncmethod to finish its job?
我怎样才能等待一个void async方法完成它的工作?
for example, I have a function like below:
例如,我有一个如下所示的功能:
async void LoadBlahBlah()
{
await blah();
...
}
now I want to make sure that everything has been loaded before continuing somewhere else.
现在我想确保在继续其他地方之前已经加载了所有内容。
采纳答案by Rohit Sharma
Best practice is to mark function async voidonly if it is fire and forget method, if you want to await on, you should mark it as async Task.
最佳做法是async void仅在函数是即发即弃方法时才标记函数,如果要等待,则应将其标记为async Task.
In case if you still want to await, then wrap it like so await Task.Run(() => blah())
如果你仍然想等待,那么就这样包装它 await Task.Run(() => blah())
回答by MBZ
回答by Mayank
You don't really need to do anything manually, awaitkeyword pauses the function execution until blah()returns.
你真的不需要手动做任何事情,await关键字会暂停函数执行直到blah()返回。
private async void SomeFunction()
{
var x = await LoadBlahBlah(); <- Function is not paused
//rest of the code get's executed even if LoadBlahBlah() is still executing
}
private async Task<T> LoadBlahBlah()
{
await DoStuff(); <- function is paused
await DoMoreStuff();
}
Tis type of object blah()returns
T是blah()返回的对象类型
You can't really awaita voidfunction so LoadBlahBlah()cannot be void
你不能真正await成为一个void函数,所以LoadBlahBlah()不能成为void
回答by Stephen Cleary
The best solution is to use async Task. You should avoid async voidfor several reasons, one of which is composability.
最好的解决方案是使用async Task. 您应该async void出于多种原因避免使用,其中之一是可组合性。
If the method cannotbe made to return Task(e.g., it's an event handler), then you can use SemaphoreSlimto have the method signal when it is about to exit. Consider doing this in a finallyblock.
如果该方法无法返回Task(例如,它是一个事件处理程序),那么您可以使用SemaphoreSlim该方法在即将退出时发出信号。考虑在finally块中执行此操作。
回答by user2712345
do a AutoResetEvent, call the function then wait on AutoResetEvent and then set it inside async void when you know it is done.
做一个 AutoResetEvent,调用函数然后等待 AutoResetEvent,然后当你知道它完成时将它设置在 async void 中。
You can also wait on a Task that returns from your void async
您还可以等待从无效异步返回的任务
回答by Droa
I know this is an old question, but this is still a problem I keep walking into, and yet there is still no clear solution to do this correctly when using async/await in an async void signature method.
我知道这是一个老问题,但这仍然是我不断遇到的问题,但在异步无效签名方法中使用 async/await 时,仍然没有明确的解决方案可以正确执行此操作。
However, I noticed that .Wait() is working properly inside the void method.
但是,我注意到 .Wait() 在 void 方法中正常工作。
and since async void and void have the same signature, you might need to do the following.
由于 async void 和 void 具有相同的签名,您可能需要执行以下操作。
void LoadBlahBlah()
{
blah().Wait(); //this blocks
}
Confusingly enough async/await does not block on the next code.
令人困惑的是 async/await 不会阻塞下一个代码。
async void LoadBlahBlah()
{
await blah(); //this does not block
}
When you decompile your code, my guess is that async void creates an internal Task (just like async Task), but since the signature does not support to return that internal Tasks
当你反编译你的代码时,我的猜测是 async void 创建了一个内部任务(就像异步任务一样),但由于签名不支持返回该内部任务
this means that internally the async void method will still be able to "await" internally async methods. but externally unable to know when the internal Task is complete.
这意味着在内部 async void 方法仍然能够“等待”内部异步方法。但外部无法知道内部任务何时完成。
So my conclusion is that async void is working as intended, and if you need feedback from the internal Task, then you need to use the async Task signature instead.
所以我的结论是 async void 按预期工作,如果您需要来自内部 Task 的反馈,那么您需要改用 async Task 签名。
hopefully my rambling makes sense to anybody also looking for answers.
希望我的漫无边际对任何也在寻找答案的人都有意义。
Edit: I made some example code and decompiled it to see what is actually going on.
编辑:我制作了一些示例代码并对其进行反编译以查看实际发生的情况。
static async void Test()
{
await Task.Delay(5000);
}
static async Task TestAsync()
{
await Task.Delay(5000);
}
Turns into (edit: I know that the body code is not here but in the statemachines, but the statemachines was basically identical, so I didn't bother adding them)
变成(编辑:我知道主体代码不在此处而是在状态机中,但状态机基本相同,所以我没有费心添加它们)
private static void Test()
{
<Test>d__1 stateMachine = new <Test>d__1();
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
<TestAsync>d__2 stateMachine = new <TestAsync>d__2();
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
neither AsyncVoidMethodBuilder or AsyncTaskMethodBuilder actually have any code in the Start method that would hint of them to block, and would always run asynchronously after they are started.
AsyncVoidMethodBuilder 或 AsyncTaskMethodBuilder 实际上在 Start 方法中没有任何代码会提示它们阻塞,并且在它们启动后总是异步运行。
meaning without the returning Task, there would be no way to check if it is complete.
意思是没有返回的任务,就没有办法检查它是否完成。
as expected, it only starts the Task running async, and then it continues in the code. and the async Task, first it starts the Task, and then it returns it.
正如预期的那样,它只启动异步运行的任务,然后在代码中继续运行。和异步任务,首先启动任务,然后返回它。
so I guess my answer would be to never use async void, if you need to know when the task is done, that is what async Task is for.
所以我想我的答案是永远不要使用 async void,如果您需要知道任务何时完成,这就是 async Task 的用途。

