如何等待异步方法完成?

时间:2013-03-01 03:07:07

标签: c# asynchronous async-await

我正在编写一个将数据传输到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循环?

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

7 个答案:

答案 0 :(得分:192)

了解asyncawait最重要的事情是await 等待关联的调用完成。 await做的是立即和同步返回操作的结果如果操作已经完成,或者如果没有,则安排继续执行{的其余部分{1}}方法然后将控制权返回给调用者。异步操作完成后,将执行计划完成。

问题标题中特定问题的答案是通过调用适当的{{async方法的返回值(应该是asyncTask类型)来阻止它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.")