C# async Wait如何在使用事件循环的应用程序(如Windows窗体)中允许响应?

C# async Wait如何在使用事件循环的应用程序(如Windows窗体)中允许响应?,c#,.net,winforms,asynchronous,async-await,C#,.net,Winforms,Asynchronous,Async Await,据我所知,UI应用程序有一个主线程,其循环相当于 while(true) { var e = events.Dequeue(); // get event from the queue e(); // run event } 我很困惑e()如果位于async-wait链的顶部,它将被“解锁”。假设e()最终调用 public async Task WaitOneSecondAsync() { await Task.Delay(1000); Console.Write

据我所知,UI应用程序有一个主线程,其循环相当于

while(true)
{
   var e = events.Dequeue(); // get event from the queue
   e(); // run event
}
我很困惑
e()
如果位于
async
-
wait
链的顶部,它将被“解锁”。假设
e()
最终调用

public async Task WaitOneSecondAsync()
{
    await Task.Delay(1000);
    Console.WriteLine("Done waiting 1 second!");
}
一旦主线程点击
wait Task.Delay(1000)它不会“继续”到
的下一个迭代,而
循环。你能解释一下这是怎么解锁的吗?也许有一个代码示例

一旦主线程命中wait Task.Delay(1000);它不会“继续”到while循环的下一个迭代

是的,会的

记住,任务。延迟不是线程。睡眠。睡眠会关闭你的线程,直到它再次醒来才会回来。Task.Delay立即返回表示延迟的任务

你能解释一下这是怎么解锁的吗

wait
具有以下行为:

  • 检查任务是否已完成。如果是,并且它已完成并出现异常,则抛出异常。如果是,并且正常完成,则生成值(如果有),并继续正常执行
  • 任务尚未完成。创建一个委托,其操作是在等待点再次开始运行此方法。(这是编译器要做的一件棘手的事情;请参阅任何关于Wait codegen详细信息的文章以获得解释。)注册该委托作为任务的继续,然后返回调用方
  • 如果这是方法中遇到的第一个等待,则返回的是表示方法工作流的任务,以便调用方可以依次等待它

具有以下伪代码语义:

    Task thisTask = a new task;
    Action completion = () => { 
      Console.WriteLine("Done..."); 
      mark thisTask as complete
    };
    Task delayTask = Task.Delay(1000);
    if (delayTask has already completed normally)
    {
        completion();
        return thisTask; // Return a completed task.
    }
    else if (delayTask completed with an exception)
        throw the exception
    else
        assign completion as the completion of delayTask
        return thisTask;
看到了吗?如果延迟尚未完成,则该方法注册一个委托作为延迟的完成,返回给调用方。如果调用方是消息循环,那么消息循环将再次运行

延迟完成后会发生什么它将一条消息排入队列,上面写着调用其完成,完成将在将来的某个时间运行


当然,真正的codegen比我在这里展示的小伪代码要复杂得多;那只是为了让大家明白这个想法。真正的代码生成是复杂的,因为异常处理比仅仅抛出异常更困难,并且在可能的情况下延迟在堆上生成对象的各种优化;它不会“继续”到while循环的下一个迭代。
是的,它会。这就是异步方法的全部要点。它们不会阻塞;他们立即返回(或接近返回),让呼叫者继续做他们想做的事情。可能重复的是。这正是它要做的。当代码点击wait
Task.Delay
时,它将把其余的
WaitOneSecondAsync
配置为一个延续,然后将控制权交给调用方,调用方在while循环中。当
Task.Delay
完成时,延续(即
WaitOneSecondAsync
的其余部分)将自身添加到事件队列中。您可以使用WaitOne取消阻止。看msdn:你有没有对这个问题做过研究?有很多文章介绍了这是如何工作的。
    Task thisTask = a new task;
    Action completion = () => { 
      Console.WriteLine("Done..."); 
      mark thisTask as complete
    };
    Task delayTask = Task.Delay(1000);
    if (delayTask has already completed normally)
    {
        completion();
        return thisTask; // Return a completed task.
    }
    else if (delayTask completed with an exception)
        throw the exception
    else
        assign completion as the completion of delayTask
        return thisTask;