简体   繁体   English

如何等待异步方法完成?

[英]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.关于asyncawait最重要的事情是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方法的返回值(应为TaskTask<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM