当前位置:  开发笔记 > 编程语言 > 正文

这是我在理解async-await时的最后一次尝试.我对么?

如何解决《这是我在理解async-await时的最后一次尝试.我对么?》经验,为你挑选了1个好方法。

我想我终于在以下段落之后理解了它

如果使用或async修饰符标记方法,则可以在方法中使用await运算符.当控制在异步方法中到达await表达式时,控制权返回给调用者,并且方法中的进度将暂停,直到等待的任务完成.任务完成后,可以在方法中恢复执行.

它来自http://blogs.msdn.com/b/csharpfaq/archive/2012/06/26/understanding-a-simple-async-program.aspx.

所以,假设我有一个功能

public void Caller ( ) 
{
    Something1();
    SomeAsyncMethod();
    Something2();
    Something3();
    Something4();
}

public async void SomeAsyncMethod ( )
{
    Task getWebPageTask = GetWebPageAsync("http://stackoverflow.com");
    Console.WriteLine("Begin");
    string task = await getWebPageTask;
    Console.WriteLine("End");
    // return 
}

为了论证,让我们说一下完成task我在下面指定的行所需的时间

    Something2();
    Something3();
    // task would be done at this point
    Something4();

然后执行流程实际上就像

    Something1();
    Task getWebPageTask = GetWebPageAsync("http://stackoverflow.com");
    Console.WriteLine("Begin");
    Something2();
    Something3();
    string task = [ string returned by GetWebPageAsync("http://stackoverflow.com") ] 
    Console.WriteLine("End");
    Something4();

所以它很像一个yield声明,因为执行在方法的调用者和方法体之间切换.

我现在明白了吗?



1> Eric Lippert..:

我现在明白了吗?

不,不完全.存储的任务的完成getWebPageTask不会导致当前运行的线程Something3丢弃正在执行的操作并运行其余部分SomeAsyncMethod.(除非有一些真正奇怪的事情发生,比如其中一种方法在抽取消息循环.)

相反,延续计划在未来某个未指定的时间运行.

这是如何运作的?假设您使用的是Windows窗体应用程序,因为这很容易理解.你可能已经注意到在winforms应用程序中,一切都是"事件驱动的".也就是说,当事件发生时,事件处理程序会以某种方式神秘地执行.这不是魔术.顶部有一个循环,它将消息队列中的窗口消息拉出,解码它们,并确定是否有与之关联的事件处理程序.如果有则处理程序运行; 它只是一个普通的方法调用.

当任务在Windows窗体应用程序中完成时,它会在队列中放入一条消息,表示"刚刚发生了任务完​​成事件;当您处理此消息时,请调用此延续".

这就是为什么将来会在某个时间调用continuation的原因- 消息循环不会再次运行,直到它刚刚调用的所有代码都返回给它.如果任务在发生时完成,则消息将位于队列中以便按顺序处理.

现在,其他控制流程也是可能的.您可以配置一个线程,以便在该线程启动的任务完成时,计划在将来在任务管理器选择的工作线程上运行完成.但是,在我们跑步之前,让我们走吧; 在尝试弄清楚它在多个线程上是如何工作之前,请确保您了解它在一个线程如何工作的.

假设您的Caller方法由消息循环调用,单线程异步程序中的实际控制流将如下所示:

message loop invokes Caller
    Caller invokes Something1
        Something1 returns 
    Caller invokes SomeAsyncMethod
        SomeAsyncMethod invokes GetWebPageAsync
            GetWebPageAsync starts fetching a web page and returns a task
        SomeAsyncMethod stores the task
        SomeAsyncMethod writes Begin
        SomeAsyncMethod checks whether the task completed. Let's suppose it did not.
        SomeAsyncMethod makes a delegate that writes "End" and assigns it as the continuation to the task (*)
        SomeAsyncMethod returns
    Caller invokes Something2, which returns
    Caller invokes Something3, which returns
    Suppose at this point the task completes. The IO system queues up a message. (**)
    Caller invokes Something4, which returns
    Caller returns
If there are messages queued up before the completion message, they are processed.
Eventually the message loop sees that there is a queued message saying that a task has completed. It invokes the completion.
    "End" is written.
    The completion returns.
The message loop keeps on pumping messages and doing work.

(*)这是一个过度紧张的谎言.制作的实际代表要复杂得多.

(**)这也有点过于简单化了,但它得到了一个想法.

现在,读者会仔细询问"如果该线程忙于调用,该任务究竟如何将消息放入消息队列中Something3?当然,这就像处理器在Something3运行时简单地插入延续时一样是不可能的,对吧?这实际上并不是神奇的 - 虽然它比平凡的事件循环更加神奇! - 并且在Stephen Cleary的文章"没有线程"中有解释,我建议你阅读.

推荐阅读
周扒pi
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有