C# 如何等待异步方法完成?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15149811/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 14:16:44  来源:igfitidea点击:

How to wait for async method to complete?

c#asynchronousasync-await

提问by bmt22033

I'm writing a WinForms application that transfers data to a USB HID class device. My application uses the excellent Generic HID library v6.0 which can be found here. In a nutshell, when I need to write data to the device, this is the code that gets called:

我正在编写一个将数据传输到 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();
    }
}

When my code drops out of the while loop, I need to read some data from the device. 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:

当我的代码退出 while 循环时,我需要从设备读取一些数据。但是,设备无法立即响应,因此我需要等待此调用返回,然后才能继续。由于它目前存在,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. 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?

不幸的是,我不太熟悉 .NET 4.5 中新的 async/await 技术的工作原理。我之前阅读了一些关于 await 关键字的内容,这给我的印象是在 RequestToGetInputReport() 内部调用 GetInputReportViaInterruptTransfer() 会等待(也许它会等待?)但它似乎不像对 RequestToGetInputReport() 的调用本身正在等待,因为我似乎几乎立即重新进入 while 循环?

Can anyone clarify the behavior that I'm seeing?

任何人都可以澄清我所看到的行为吗?

采纳答案by Stephen Cleary

Avoid async void. Have your methods return Taskinstead of void. Then you can awaitthem.

避免async void。让您的方法返回Task而不是void. 然后你就可以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();
}

回答by Richard Cook

The most important thing to know about asyncand awaitis that awaitdoesn'twait for the associated call to complete. What awaitdoes is to return the result of the operation immediately and synchronously if the operation has already completedor, if it hasn't, to schedule a continuation to execute the remainder of the asyncmethod and then to return control to the caller. When the asynchronous operation completes, the scheduled completion will then execute.

最重要的是要了解asyncawaitawait等待完成相关的呼叫。什么await做的是立即地,同步返回操作的结果如果操作已经完成,或者,如果没有,安排的延续,执行的剩余async方法,然后将控制返回给调用者。异步操作完成后,将执行计划完成。

The answer to the specific question in your question's title is to block on an asyncmethod's return value (which should be of type Taskor Task<T>) by calling an appropriate Waitmethod:

问题标题中特定问题的答案是通过调用适当的方法来阻止async方法的返回值(应为Task或类型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;
}

In this code snippet, CallGetFooAsyncAndWaitOnResultis a synchronouswrapper around asynchronous method 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.

在此代码片段中,CallGetFooAsyncAndWaitOnResult是异步方法的同步包装器GetFooAsync。但是,在大多数情况下应避免这种模式,因为它会在异步操作期间阻塞整个线程池线程。这是对 API 公开的各种异步机制的低效使用,而这些异步机制付出了巨大的努力来提供它们。

The answer at "await" doesn't wait for the completion of callhas several, more detailed, explanations of these keywords.

“await”处的答案不等待调用完成,对这些关键字有几个更详细的解释。

Meanwhile, @Stephen Cleary's guidance about async voidholds. 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

同时,@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

回答by Jerther

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.")

回答by Ram chittala

Best Solution to wait AsynMethod till complete the task is

等待 AsynMethod 直到完成任务的最佳解决方案是

var result = Task.Run(async() => await yourAsyncMethod()).Result;

回答by Bar?? Tanyeri

Actually I found this more helpful for functions that return IAsyncAction.

实际上我发现这对返回 IAsyncAction 的函数更有帮助。

            var task = asyncFunction();
            while (task.Status == AsyncStatus.Completed) ;

回答by Firas Nizam

just put Wait() to wait until task completed

只需放置 Wait() 等待任务完成

GetInputReportViaInterruptTransfer().Wait();

GetInputReportViaInterruptTransfer().Wait();

回答by shocky lemi

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();
}