我正在编写一个将数据传输到USB HID类设备的WinForms应用程序。我的应用程序使用了优秀的Generic HID库v6.0,可以找到here。简而言之,当我需要将数据写入设备时,这就是被调用的代码:
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中新的async / await技术的工作原理。我之前对await关键字进行了一些阅读,这给我的印象是RequestToGetInputReport()内部对GetInputReportViaInterruptTransfer()的调用会等待(也许它会这样做?)但它似乎不是对RequestToGetInputReport()的调用本身正在等待,因为我似乎几乎立即重新进入while循环?
任何人都可以澄清我所看到的行为吗?
答案 0 :(得分:192)
了解async
和await
最重要的事情是await
不等待关联的调用完成。 await
做的是立即和同步返回操作的结果如果操作已经完成,或者如果没有,则安排继续执行{的其余部分{1}}方法然后将控制权返回给调用者。异步操作完成后,将执行计划完成。
问题标题中特定问题的答案是通过调用适当的{{async
方法的返回值(应该是async
或Task
类型)来阻止它1}}方法:
Task<T>
在此代码段中,Wait
是围绕异步方法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;
}
的同步包装器。但是,大多数情况下应避免使用此模式,因为它将在异步操作期间阻塞整个线程池线程。这是对API公开的各种异步机制的低效使用,它们努力提供它们。
"await" doesn't wait for the completion of call的答案有几个更详细的解释。
与此同时,@ Stete Cleary关于CallGetFooAsyncAndWaitOnResult
的指导仍然存在。其他很好的解释可以在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找到。
答案 1 :(得分:111)
避免使用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();
}
答案 2 :(得分:52)
等待AsynMethod直到完成任务的最佳解决方案
var result = Task.Run(async() => { return await yourAsyncMethod(); }).Result;
答案 3 :(得分:0)
只需将Wait()放到任务完成即可
GetInputReportViaInterruptTransfer().Wait();
答案 4 :(得分:0)
以下是使用标志的解决方法:
//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();
}
答案 5 :(得分:-1)
实际上,我发现这对于返回IAsyncAction的函数更有用。
var task = asyncFunction();
while (task.Status == AsyncStatus.Completed) ;
答案 6 :(得分:-5)
以下代码段显示了一种确保等待方法在返回调用方之前完成的方法。但是,我不会说这是好习惯。如果您不这么认真,请用解释编辑我的答案。
public async Task AnAsyncMethodThatCompletes()
{
await SomeAsyncMethod();
DoSomeMoreStuff();
await Task.Factory.StartNew(() => { }); // <-- This line here, at the end
}
await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")