如何等待asynchronous方法来完成?
我正在写一个WinForms应用程序,将数据传输到USB HID类设备。 我的应用程序使用优秀的通用HID库v6.0,可以在这里find。 简而言之,当我需要将数据写入设备时,这是被调用的代码:
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(); } }
当我的代码退出while循环时,我需要从设备读取一些数据。 但是,设备无法立即响应,所以我需要等待这个电话才能继续。 由于它现在存在,所以RequestToGetInputReport()被声明如下:
private async void RequestToGetInputReport() { // lots of code prior to this int bytesRead = await GetInputReportViaInterruptTransfer(); }
对于它的价值,GetInputReportViaInterruptTransfer()的声明如下所示:
internal async Task<int> GetInputReportViaInterruptTransfer()
不幸的是,我对.NET 4.5中新的asynchronous/等待技术的工作并不是很熟悉。 我早些时候对await关键字做了一些阅读,这让我觉得在RequestToGetInputReport()内部调用GetInputReportViaInterruptTransfer()会等待(也许它呢?),但是对于RequestToGetInputReport()本身正在等待,因为我似乎几乎立即重新进入while循环?
任何人都可以澄清我看到的行为?
避免async void
。 让你的方法返回Task
而不是void
。 那么你可以await
他们。
喜欢这个:
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(); }
了解async
和await
最重要的是, await
不等待相关的呼叫完成。 await
操作是, 如果操作已经完成 ,则立即返回操作的结果,或者如果没有,则继续执行async
方法的其余部分,然后将控制返回给调用者。 当asynchronous操作完成时,计划完成将会执行。
问题标题中特定问题的答案是通过调用适当的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; }
在这段代码中, CallGetFooAsyncAndWaitOnResult
是asynchronous方法GetFooAsync
的同步包装。 但是,这种模式大部分都是要避免的,因为在asynchronous操作期间它会阻塞整个线程池线程。 这是对API暴露的各种asynchronous机制的低效使用,这些asynchronous机制付出巨大的努力来提供这些机制。
在“等待”的答案并不等待完成调用有几个,更详细的解释这些关键字。
同时,@Stephen Cleary关于async void
的指导是成立的。 其他很好的解释为什么可以在http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/和http://www.jaylee.org/ post / 2012/07/08 / c-sharp-async-tips-and-tricks-part-2-async-void.aspx 。
等待AsynMethod完成任务的最佳解决scheme
var result = Task.Run(async() => { return await yourAsyncMethod(); }).Result;
下面的代码片断显示了一种方法来确保等待的方法在返回给调用者之前完成。 不过,我不会说这是好的做法。 如果您不这么想,请编辑我的答案和解释。
public async Task AnAsyncMethodThatCompletes() { await SomeAsyncMethod(); DoSomeMoreStuff(); await Task.Factory.StartNew(() => { }); // <-- This line here, at the end } await AnAsyncMethodThatCompletes(); Console.WriteLine("AnAsyncMethodThatCompletes() completed.")