目标实现无栈协程,这需要编译器能自动将异步函数编译为异步状态机
考虑下方函数:
async fn test() {
let a = 1;
await some_async_io();
a = a + 1;
}
在编译的时候,test会变成:
struct test_ctx{
step:i64;
a: i64;
}
fn test_init() test_ctx {
return test_ctx{};
}
fn test_move_next(ctx: test_ctx) bool {
switch ctx.step {
case 0:
ctx.a = 1;
event_loop_register(some_async_io);
case 1:
ctx.a = ctx.a + 1;
}
ctx.step += 1;
return ctx.step == 1;
}
在调用test的时候,生成代码为:
let ctx = test_init();
test_move_next(ctx);
event_loop_register会把异步操作注册到evloop里,在该操作完成之后,evloop会通知调度器,调度器继续执行test_move_next(ctx)
为了保证gc正确性,evloop线程不要跑pl代码或者函数,只跑rust代码。
关于调度器
我们把异步状态机记为Task,那么一个纯异步程序中(main也是async的),实际上所有线程都不是直接跑用户代码,而是运行调度器,而调度器对用户代码进行调度和运行。
下方假设我们使用一个全局的task 队列,那么调度器伪代码如下:
loop {
let task = queue.dequeue();
if task != null {
task.move_next();
}
}
evloop在一个异步操作完成后,需要queue.enqueue(task)
目标实现无栈协程,这需要编译器能自动将异步函数编译为异步状态机
考虑下方函数:
在编译的时候,test会变成:
在调用test的时候,生成代码为:
event_loop_register会把异步操作注册到evloop里,在该操作完成之后,evloop会通知调度器,调度器继续执行test_move_next(ctx)
为了保证gc正确性,evloop线程不要跑pl代码或者函数,只跑rust代码。
关于调度器
我们把异步状态机记为Task,那么一个纯异步程序中(main也是async的),实际上所有线程都不是直接跑用户代码,而是运行调度器,而调度器对用户代码进行调度和运行。
下方假设我们使用一个全局的task 队列,那么调度器伪代码如下:
evloop在一个异步操作完成后,需要
queue.enqueue(task)