[英]How to wait for async method to complete?
I'm writing a WinForms application that transfers data to a USB HID class device.我正在编写一个将数据传输到 USB HID 类设备的 WinForms 应用程序。 My application uses the excellent Generic HID library v6.0 which can be found here .我的应用程序使用了优秀的通用 HID 库 v6.0,可以在这里找到。 In a nutshell, when I need to write data to the device, this is the code that gets called:简而言之,当我需要将数据写入设备时,这是调用的代码:
private async void RequestToSendOutputReport(List<byte[]> byteArrays)
{
foreach (byte[] b in byteArrays)
{
while (condition)
{
// we'll typically execute this code many times until the condition is no longer met
Task t = SendOutputReportViaInterruptTransfer();
await t;
}
// read some data from device; we need to wait for this to return
RequestToGetInputReport();
}
}
When my code drops out of the while loop, I need to read some data from the device.当我的代码退出 while 循环时,我需要从设备读取一些数据。 However, the device isn't able to respond right away so I need to wait for this call to return before I continue.但是,设备无法立即响应,因此我需要等待此调用返回,然后才能继续。 As it currently exists, RequestToGetInputReport() is declared like this:由于它目前存在,RequestToGetInputReport() 声明如下:
private async void RequestToGetInputReport()
{
// lots of code prior to this
int bytesRead = await GetInputReportViaInterruptTransfer();
}
For what it's worth, the declaration for GetInputReportViaInterruptTransfer() looks like this:值得一提的是,GetInputReportViaInterruptTransfer() 的声明如下所示:
internal async Task<int> GetInputReportViaInterruptTransfer()
Unfortunately, I'm not very familiar with the workings of the new async/await technologies in .NET 4.5.不幸的是,我不太熟悉 .NET 4.5 中新的 async/await 技术的工作原理。 I did a little reading earlier about the await keyword and that gave me the impression that the call to GetInputReportViaInterruptTransfer() inside of RequestToGetInputReport() would wait (and maybe it does?) but it doesn't seem like the call to RequestToGetInputReport() itself is waiting because I seem to be re-entering the while loop almost immediately?我之前阅读了一些关于 await 关键字的内容,这给我的印象是在 RequestToGetInputReport() 中调用 GetInputReportViaInterruptTransfer() 会等待(也许它会等待?)但它似乎不像是对 RequestToGetInputReport() 的调用本身正在等待,因为我似乎几乎立即重新进入 while 循环?
Can anyone clarify the behavior that I'm seeing?任何人都可以澄清我所看到的行为吗?
The most important thing to know about async
and await
is that await
doesn't wait for the associated call to complete.关于async
和await
最重要的事情是await
不等待关联的调用完成。 What await
does is to return the result of the operation immediately and synchronously if the operation has already completed or, if it hasn't, to schedule a continuation to execute the remainder of the async
method and then to return control to the caller. await
所做的是在操作已经完成时立即并同步地返回操作的结果,或者,如果尚未完成,则安排继续执行async
方法的其余部分,然后将控制权返回给调用者。 When the asynchronous operation completes, the scheduled completion will then execute.异步操作完成后,将执行计划完成。
The answer to the specific question in your question's title is to block on an async
method's return value (which should be of type Task
or Task<T>
) by calling an appropriate Wait
method:问题标题中特定问题的答案是通过调用适当的Wait
方法来阻止async
方法的返回值(应为Task
或Task<T>
):
public static async Task<Foo> GetFooAsync()
{
// Start asynchronous operation(s) and return associated task.
...
}
public static Foo CallGetFooAsyncAndWaitOnResult()
{
var task = GetFooAsync();
task.Wait(); // Blocks current thread until GetFooAsync task completes
// For pedagogical use only: in general, don't do this!
var result = task.Result;
return result;
}
In this code snippet, CallGetFooAsyncAndWaitOnResult
is a synchronous wrapper around asynchronous method GetFooAsync
.在此代码片段中, CallGetFooAsyncAndWaitOnResult
是异步方法GetFooAsync
的同步包装器。 However, this pattern is to be avoided for the most part since it will block a whole thread pool thread for the duration of the asynchronous operation.但是,在大多数情况下应避免这种模式,因为它会在异步操作期间阻塞整个线程池线程。 This an inefficient use of the various asynchronous mechanisms exposed by APIs that go to great efforts to provide them.这是对 API 公开的各种异步机制的低效使用,而这些异步机制付出了巨大的努力来提供它们。
The answer at "await" doesn't wait for the completion of call has several, more detailed, explanations of these keywords. “await”处的答案不等待调用完成,对这些关键字有几个更详细的解释。
Meanwhile, @Stephen Cleary's guidance about async void
holds.同时,@Stephen Cleary 关于async void
的指导也成立。 Other nice explanations for why can be found at http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/ and https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html关于原因的其他很好的解释可以在http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/和https://jaylee.org/archive/找到2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html
Avoid async void
.避免async void
。 Have your methods return Task
instead of void
.让您的方法返回Task
而不是void
。 Then you can await
them.然后你就可以await
他们。
Like this:像这样:
private async Task RequestToSendOutputReport(List<byte[]> byteArrays)
{
foreach (byte[] b in byteArrays)
{
while (condition)
{
// we'll typically execute this code many times until the condition is no longer met
Task t = SendOutputReportViaInterruptTransfer();
await t;
}
// read some data from device; we need to wait for this to return
await RequestToGetInputReport();
}
}
private async Task RequestToGetInputReport()
{
// lots of code prior to this
int bytesRead = await GetInputReportViaInterruptTransfer();
}
等待 AsynMethod 直到完成任务的最佳解决方案是
var result = Task.Run(async() => await yourAsyncMethod()).Result;
只需放置 Wait() 等待任务完成
GetInputReportViaInterruptTransfer().Wait();
Here is a workaround using a flag:这是使用标志的解决方法:
//outside your event or method, but inside your class
private bool IsExecuted = false;
private async Task MethodA()
{
//Do Stuff Here
IsExecuted = true;
}
.
.
.
//Inside your event or method
{
await MethodA();
while (!isExecuted) Thread.Sleep(200); // <-------
await MethodB();
}
The following snippet shows a way to ensure the awaited method completes before returning to the caller.以下代码段显示了一种确保等待的方法在返回调用者之前完成的方法。 HOWEVER, I wouldn't say it's good practice.但是,我不会说这是一种很好的做法。 Please edit my answer with explanations if you think otherwise.如果您不这么认为,请编辑我的答案并解释。
public async Task AnAsyncMethodThatCompletes()
{
await SomeAsyncMethod();
DoSomeMoreStuff();
await Task.Factory.StartNew(() => { }); // <-- This line here, at the end
}
await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")
Actually I found this more helpful for functions that return IAsyncAction.实际上我发现这对返回 IAsyncAction 的函数更有帮助。
var task = asyncFunction();
while (task.Status == AsyncStatus.Completed) ;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.