当前位置: 首页 > 知识库问答 >
问题:

如何等待异步方法完成?

吴经略
2023-03-14

我正在编写一个WinForms应用程序,它将数据传输到USB HID类设备。我的应用程序使用了优秀的通用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()

不幸的是,我不太熟悉.NET4.5中新的Async/Await技术的工作原理。我在前面读了一些关于await关键字的文章,这给我的印象是RequestToGetInputReport()中对getInputReport()中的GetInputReportViaInterruptTransfer()的调用将等待(也许是这样的?)但对RequestToGetInputReport()的调用本身似乎并不等待,因为我似乎几乎立即重新进入while循环?

谁能澄清一下我看到的行为吗?

共有3个答案

傅星光
2023-03-14

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

var result = Task.Run(async() => await yourAsyncMethod()).Result;
祁飞翰
2023-03-14

关于asyncawait最重要的一点是,await不会等待关联的调用完成。await所做的是,如果操作已经完成,await立即同步返回操作的结果,如果还没有完成,则安排继续执行async方法的剩余部分,然后将控制权返回给调用方。当异步操作完成时,将执行预定的完成。

问题标题中特定问题的答案是通过调用适当的wait方法阻止async方法的返回值(该返回值应为tasktask ):

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所公开的各种异步机制的低效使用,而API花了很大的力气来提供这些机制。

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

同时,@Stephen Cleary关于Async void的指导也成立。有关原因的其他解释可以在http://www.tonicodes.net/blog/why-you-should-arment-never-write-void-asynchronous-methods/和https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html上找到

燕正卿
2023-03-14

避免async void。让您的方法返回task而不是void。然后您可以aite它们。

像这样:

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();
}
 类似资料:
  • 我通读了Dart/flatter中的Async/Await/then,试图理解为什么aysnc函数中的Await不会等到完成后再继续。在我的UI中,有一个按钮调用一个异步方法来返回一个位置,该位置总是返回null,并且不等待函数完成。 该函数将调用推送到一个新的UI页面,该页面选择一个位置,并应返回一个结果。如何使该函数等待结果?我不是在使用异步吗?

  • 在C#中使用时,一般的规则是避免,因为这几乎是一个错误,如果方法没有发送返回值,则应该使用。有道理。奇怪的是,在本周早些时候,我为我编写的一些方法编写了一些单元测试,并注意到NUnit建议将测试标记为或返回。然后我试了一下,果然奏效了。这似乎真的很奇怪,因为nunit框架如何能够运行该方法并等待所有异步操作完成?如果它返回Task,它可以等待任务,然后做它需要做的事情,但是如果它返回void,它如

  • 在实际应用中,我对 C# 中的异步和 await 方法进行了说明。请考虑以程,这是工作代码的简单版本: 助手.cs 功能控制器.cs processing.js 现在,问题是第三方服务的所需时间更少(例如:2秒),而所需的时间更多(例如:100秒)。进行两个ajax调用并使用异步和等待是为了呈现自我。屏幕上显示数据1,不要等到自己。Data2已被检索。不幸的是,这种情况没有发生,我必须等待100秒

  • 我试图在react/electron项目中使用async/await,但它不起作用。我想要的是获取docker容器状态列表。但是安慰。日志(列表)返回未定义的。 有人能帮我吗?:)

  • 问题内容: 我知道这个问题以前曾被问过,但是所有解决方案都不适合我。 我有一个将参数发送到API的函数,并以列表的形式返回数据。我有一个UITableView设置为使用该列表,但是它在列表分配给变量之前运行。 码: 如果不立即将其作为重复投票,我将不胜感激,这是我尝试的方法。 派遣组 信号量计时 运行变量 其中包括= self和= self 。 编辑:要求提取项目, 问题答案: 您不能-也不应该-

  • 问题内容: 嗨,我的脚本中有2个Ajax调用,我需要它们运行asnyc以节省时间,但是我需要第二个才能等待第一个完成。 有什么想法吗?谢谢 问题答案: 如果使用jQuery 1.5+,则可以使用jQuery 完成。诸如此类的东西(缩短了ajax的简洁性,只需像上面那样传递对象) 您不知道它们将以什么顺序返回,因此,如果您手动滚动此请求,则需要检查另一个请求的状态并等待它返回。