[英]How to wait for async method to complete?
我正在編寫一個將數據傳輸到 USB HID 類設備的 WinForms 應用程序。 我的應用程序使用了優秀的通用 HID 庫 v6.0,可以在這里找到。 簡而言之,當我需要將數據寫入設備時,這是調用的代碼:
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 循環?
任何人都可以澄清我所看到的行為嗎?
關於async
和await
最重要的事情是await
不等待關聯的調用完成。 await
所做的是在操作已經完成時立即並同步地返回操作的結果,或者,如果尚未完成,則安排繼續執行async
方法的其余部分,然后將控制權返回給調用者。 異步操作完成后,將執行計划完成。
問題標題中特定問題的答案是通過調用適當的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
是異步方法GetFooAsync
的同步包裝器。 但是,在大多數情況下應避免這種模式,因為它會在異步操作期間阻塞整個線程池線程。 這是對 API 公開的各種異步機制的低效使用,而這些異步機制付出了巨大的努力來提供它們。
“await”處的答案不等待調用完成,對這些關鍵字有幾個更詳細的解釋。
同時,@Stephen Cleary 關於async void
的指導也成立。 關於原因的其他很好的解釋可以在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
避免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();
}
等待 AsynMethod 直到完成任務的最佳解決方案是
var result = Task.Run(async() => await yourAsyncMethod()).Result;
只需放置 Wait() 等待任務完成
GetInputReportViaInterruptTransfer().Wait();
這是使用標志的解決方法:
//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();
}
以下代碼段顯示了一種確保等待的方法在返回調用者之前完成的方法。 但是,我不會說這是一種很好的做法。 如果您不這么認為,請編輯我的答案並解釋。
public async Task AnAsyncMethodThatCompletes()
{
await SomeAsyncMethod();
DoSomeMoreStuff();
await Task.Factory.StartNew(() => { }); // <-- This line here, at the end
}
await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")
實際上我發現這對返回 IAsyncAction 的函數更有幫助。
var task = asyncFunction();
while (task.Status == AsyncStatus.Completed) ;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.