首页 新闻 会员 周边

状态机是如何恢复的?

0
悬赏园豆:50 [已解决问题] 解决于 2017-01-17 17:08

async/await是极好的异步编程的语法糖,其实是编译器生成了状态机StateMachine,可是StateMachine又是如何在任务完成之后恢复的呢?


蝌蝌的主页 蝌蝌 | 初学一级 | 园豆:158
提问于:2016-12-16 21:13
< >
分享
最佳答案
0

可以这么看,就是await后的代码由编译器编译成了一个回调方法,在状态机切换后就执行这个回调——听上去和传统的异步很像吧?其实就是通过编译器对异步回调施加了魔法而已。

顶楼的回答是具体的细节过程,如果只想知道回调的话,只要知道状态机是用来管理异步执行状态的,状态切换时会调用特定回调,而这个回调是编译器生成的后续执行代码。

收获园豆:50
Nyarlathotep | 菜鸟二级 |园豆:271 | 2017-01-03 21:03
其他回答(3)
0

坐等大神解答

| 园豆:780 (小虾三级) | 2016-12-17 09:48
0

摘录 Async Await and the Generated StateMachine 中的一段文字:

What really happens is actually something like this:

  • On compile time:
    • A structcalled StateMachine is generated
    • Contains fields to save function local state
    • A moveNext function is created which holds the entire code
    • The code is fragmented by await calls into several cases (machine states)
    • A calling code which creates and initializes this machine replaces our async function code.
  • On Runtime: 
    • A task is created to run the machine code:
    • Local variables are “lifted” into the state machine as fields.
    • Code is run until await
    • A awaited function's task is run
    • Machine state is set to next state so next code fragment will run on wakeup
    • A wake-up event is scheduled
    • MoveNext function returns (Thread is released to do other stuff (update UI))
  • When wakeup call is issued by OS: 
    • Thread which handles the await continuation is called
    • CurrentSyncContext is used to pick the correct thread to run it on.
      • This behavior can be changed by using: await task.ConfigureAwait(false);
    • Next code segment is run since next state was set before yielding control
    • Another await is scheduled, [etc.]
dudu | 园豆:31003 (高人七级) | 2016-12-17 14:03
0

当你执行一个async的方法时,这个时候就依赖于状态机中一个很简单的switch来控制流程。一般情况(IO密集)下,请求会直接进入到内核,同时由内核提供异步实现(系统提供),然后你的请求就已经由最底层的驱动来执行(由于是异步,此时此请求可能处于不同状态,排队,已经在执行,完毕等,但是不会阻止线程执行),同时执行线程会立即知道这个任务处于pending状态,因此线程资源则可以处理其他事情。同时会返回一个Task/Task<T>给调用方(这也是状态机中初始状态的case的流程)。

之后就是漫长的等待过程(相对前面处理的消耗)直到最底层驱动收取到响应,然后驱动会告知cpu数据已经准备好了,cpu会在合适的时候对数据做解包操作。然后从内核返回用户模式进入状态机中的switch(MoveNext方法,state用于记录状态),最终执行相应的代码。

cpu密集型的逻辑有些不同,在判断出此种类型后(也可能是你代码中直接给task的各种hint),此种请求会直接进入线程池队列(这里我不太明确),同时返回Task/Task<T>。然后主线程(启动task的线程)会继续后续逻辑,直到碰到针对这个task的await。于此同时通过线程池分配的线程对委托进行计算,当计算完毕或者当碰到await,底层会通过task对应的TaskAwaiter判断是否结束(如已经complete则交由状态机最后一个状态完成相应工作,否则开始通过自旋等待升级为ManualResetEventSlim(轻量级的ManualResetEvent)等待),最后拿到结果。

Daniel Cai | 园豆:10424 (专家六级) | 2016-12-19 16:54

感谢您的回答

您说的是整个异步的流程模型,而我想知道的是,这个StateMachine是如何实现的?

任务完成之后,它是如何恢复过来,继续往下执行的呢?关注点是如何实现的。

最后,再次表示感谢。


支持(0) 反对(0) 蝌蝌 | 园豆:158 (初学一级) | 2016-12-20 10:09
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册