-
Notifications
You must be signed in to change notification settings - Fork 1
9月20日学习笔记
复杂的状态机编写起来对程序员要求高
2007年,F#语言,把函数当变量来处理,函数块、程序块可赋值,可做异步编程
增加类型支持编程
底下的Runtime来支撑
kernel需要一定配合,Kernel abstraction 屏蔽kernel差异性
NodeJS V8编译器、运行时,基于此,做了扩展
Go语言,每个thread有自己的栈
回调函数越多,memory使用越大,call back很难debug,状态的保存与恢复需要管理
promise:链式编程方式
以同步的方式实现异步编程
OS需要提交事件,事件一旦ready,就会通知task
Epoll,高性能主流异步事件处理机制,只有三个函数
epoll_create():指定需要监听的IO操作
epoll_ctl():进一步设置,读监听,还是写监听
epoll_wait():事件ready了马上返回
21.2 Futures in Rust
异步编程的一种类型
Future的设计目标:零成本异步编程
调用IO时,系统调用会立即返回,然后可以继续进行其他工作
IO完成时,回到调用该异步IO暂停的那个任务线上继续执行
一种通过对异步IO的良好抽象形成的基于库的解决方案,不是语言的一部分,也不是每个程序附带的运行时的一部分,只是可选的并按需使用的库
零成本抽象:不给不使用该功能的用户增加成本;使用该功能时,它的速度不会比不使用它的速度慢
Async Architecture of rust
三部分:底层kernel IO tasks mio(kernel的抽象层,相当于中断机制,不断地产生事件,来触发等待状态的thread变成ready态,操作系统可以对thread进行进一步调度执行了) tokio(runtime,是一个special 异步的runtime,有两部分,一部分Reactor响应机制,另一部分Executor执行机制,executor调Future把数据给取回来) Future相当于thread,task任务,
Future是语言级、编译器要支持的内容,tokio、mio是runtime要支持的内容,kernel io tasks是OS要支持的内容
future最终会形成task,task会有不同的状态,如果是就绪状态的话,executor就可以执行它,如果task需要的内容没有来,pending挂起状态,executor把它放在挂起的队列里面就OK了,task会被外面的事件,OS的IO事件,通过reactor来发出一个waker,传给waker,通过waker来唤醒task,executor就会知道这个时候task已经变成ready了,executor会通过poll函数去调task
executor、reactor、waker三者的组合形成了整个architecture
future有两类:leaf futures(一个具体的IO请求,会直接向kernel发出调用) & Non-leaf futures(由一系列leaf和non-leaf组成的更大的future)
Rust有特定的库来支持:async-std、Tokio
common interface表示操作,但是没有实现,实现放在库中,灵活地把语言和库做了区分
库分了两类,标准库,具体库
21.3 Generators and async/await
生成器和异步执行
异步执行需要走走停停,程序中进行标注,编译器做更多的事
自引用数据结构和绑定
生成器:
一个进程里面并发,Rust里面给出支持
Stackful coroutines(green threads)
Using combinators 组合器
Stackless coroutines(generators)生成器,栈去掉,仍然能在里面切换执行
如何把一个异步函数,看上去像一个函数的执行
在Rust中,异步实现为一个生成器,生成器又实现为一个状态机,一个异步函数走一段停一段,停的过程,只要有停的地方,和有可能停的地方,连续的地方说成一个状态,停下来之后,恢复之后变成下一个状态,将一个函数切成若干段,每一段是可以连续执行的一个段落,切成一个状态机,在状态机之间完成一些转换,转换是由编译器来完成,从而在每一个状态变化的时候,我能知道我下一步转到哪去
转换成状态机,和状态机变迁,靠编译器来执行状态机的状态就OK,维护状态机的状态
21.4 自引用结构数据绑定
悬空指针问题
数据换地了,再引用就不对了
1、指针移动的时候,每动一次,数据就更新一遍;代价太大,Rust不采用
2、存时存起头的内容,偏移不变,起头变,不在编译时更新,在运行时更新,Rust不采用
3、Rust中禁止移动这种数据结构
在数据结构中加Pin,数据结构不允许用,由开发者来指定,开销就变小了
对一个指针的封装
好处:约定引用不会变,不会出现悬空指针
数据结构放在堆里面,在堆栈中生命周期与函数生命周期相关,所以Future中Pin数据结构放在堆里面,相对稳定一些