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

C# 如何等待异步方法完成?,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我正在编写一个WinForms应用程序,将数据传输到USB HID类设备。我的应用程序使用优秀的通用HID库v6.0,可以找到它。简而言之,当我需要向设备写入数据时,调用以下代码: private async void RequestToSendOutputReport(List<byte[]> byteArrays) { foreach (byte[] b in byteArrays) { while (condition) {

我正在编写一个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();
    }
}
值得一提的是,GetInputReportViaInterruptTransfer()的声明如下所示:

private async void RequestToGetInputReport()
{
    // lots of code prior to this
    int bytesRead = await GetInputReportViaInterruptTransfer();
}
internal async Task<int> GetInputReportViaInterruptTransfer()
内部异步任务GetInputReportViaInterruptTransfer()
不幸的是,我不太熟悉.NET4.5中新的异步/等待技术的工作原理。我之前读了一些关于wait关键字的内容,这给我的印象是,RequestToGetInputReport()中对GetInputReportViaInterruptTransfer()的调用会等待(可能会吗?),但它看起来不像是对RequestToGetInputReport()的调用它本身正在等待,因为我似乎马上就要重新进入while循环了


有人能澄清我看到的行为吗?

避免
async void
。让您的方法返回,而不是
void
。然后你就可以找到他们了

像这样:

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();
}
私有异步任务请求发送输出报告(按数组列出)
{
foreach(字节数组中的字节[]b)
{
while(条件)
{
//我们通常会多次执行此代码,直到不再满足条件为止
任务t=SendOutputReportViaInterruptTransfer();
等待t;
}
//从设备读取一些数据;我们需要等待返回
等待RequestToGetInputReport();
}
}
专用异步任务RequestToGetInputReport()
{
//在此之前有很多代码
int bytesRead=等待GetInputReportViaInterruptTransfer();
}

关于
async
await
最重要的一点是
await
不会等待相关调用完成。
await
所做的是,如果操作已经完成,立即同步返回操作结果;如果操作尚未完成,则计划继续执行
async
方法的其余部分,然后将控制权返回给调用方。异步操作完成后,将执行计划完成

问题标题中特定问题的答案是通过调用适当的
等待
方法来阻止
异步
方法的返回值(其类型应为
任务
任务
):

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;
}
公共静态异步任务GetFooAsync() { //启动异步操作并返回关联的任务。 ... } 公共静态Foo CallGetFooAsyncAndWaitOnResult() { var task=GetFooAsync(); task.Wait();//在GetFooAsync任务完成之前阻止当前线程 //仅供教学使用:一般情况下,不要这样做! var result=task.result; 返回结果; }
在此代码段中,
CallGetFooAsyncAndWaitOnResult
是异步方法
GetFooAsync
的同步包装器。但是,这种模式在很大程度上是要避免的,因为它会在异步操作期间阻塞整个线程池线程。这是对API公开的各种异步机制的低效使用,这些机制需要付出巨大的努力来提供它们

网站上的答案对这些关键词有几个更详细的解释


与此同时,@Stephen Cleary关于
async void
的指导仍然有效。下面的代码片段展示了一种确保等待的方法在返回调用方之前完成的方法。然而,我不会说这是一个好的做法。如果你不这么认为,请编辑我的答案并解释

public async Task AnAsyncMethodThatCompletes()
{
    await SomeAsyncMethod();
    DoSomeMoreStuff();
    await Task.Factory.StartNew(() => { }); // <-- This line here, at the end
}

await AnAsyncMethodThatCompletes();
Console.WriteLine("AnAsyncMethodThatCompletes() completed.")
public异步任务anasyncmethodhattomples()
{
等待SomeAsyncMethod();
DoSomeMoreStuff();

wait Task.Factory.StartNew(()=>{});//用一种方法等待任务完成的最佳解决方案是

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

实际上,我发现这对返回IAsyncation的函数更有用

            var task = asyncFunction();
            while (task.Status == AsyncStatus.Completed) ;
只需将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();
}
//在事件或方法外部,但在类内部
private bool IsExecuted=假;
专用异步任务方法A()
{
//在这里做事
IsExecuted=真;
}
.
.
.
//在您的事件或方法中
{
等待方法a();

while(!isExecuted)Thread.Sleep(200);//我发现把
await
看作是一种“异步等待”是很有用的,也就是说,它会阻止方法(如果需要的话),但不会阻止线程。因此,谈论
requesttoSendoutReport
“等待”是很有意义的
RequestToGetInputReport
即使不是阻塞等待。@Richard Cook-非常感谢您的额外解释!这应该是公认的答案,因为它更清楚地回答了实际问题(即如何在异步方法上执行线程阻塞)。最佳解决方案是异步等待,直到任务完成为var result=task.Run(异步()=>{return await yourMethod();}).Result;非常好,谢谢。我在一个类似的问题上摸不着头脑,不同之处在于,正如您所说,将
void
更改为
Task
。这是一件小事,但按照惯例,两个方法的名称都应该添加Async,例如RequestToGetInputReportAsync()如果调用者是主函数呢?@symbont:然后使用
GetAwaiter().GetResult()
@AhmedSalah
任务
表示方法的执行-因此
返回
值被放置在
任务上。结果
,异常被放置在
任务上。异常
。使用
无效
,编译器无处放置异常,因此它们只是在线程池线程上重新引发。注意o解释一下,就像我在回答中问的那样?因为就我所知,这很有效……我遇到的问题