Skip to content

异步编程详细设计

核心原则

语法与运行时分离 - 编译器只负责生成状态机,运行时由第三方实现

层面提供者内容
语言/编译器Dast 核心Future trait, async/await 语法转换
标准库可选基础运行时(参考实现)
第三方生态各种运行时实现 (tokio, async-std 等)

核心决策

基于现有设计,采用 Pull 模式 async/await(类似 Rust)


1. Future Trait 设计

基础 Trait

dast
trait Future {
    type Output

    fn poll(self: &mut Self, cx: &Context) -> Poll[Self.Output]
}

enum Poll[T] {
    Ready(T),
    Pending,
}

Context 设计

dast
struct Context {
    waker: &Waker,
}

trait Waker {
    fn wake(self: &Self)
    fn wake_by_ref(self: &Self)
}

2. async/await 语法

基础语法

dast
async fn fetch_data(url: &str) -> Result[Data, Error] {
    let response = http.get(url).await?
    let body = response.read_body().await?
    return parse(body)
}

// 调用
async fn main() {
    let data = fetch_data("https://api.example.com").await?
}

编译器转换

dast
// 源代码
async fn example() -> i32 {
    let x = async_op1().await
    let y = async_op2().await
    return x + y
}

// 编译为状态机
enum ExampleFuture {
    State0,
    State1 { x: i32 },
    State2 { x: i32, y: i32 },
    Done,
}

impl Future for ExampleFuture {
    type Output = i32

    fn poll(self: &mut Self, cx: &Context) -> Poll[i32] {
        loop {
            match self {
                .State0 => {
                    let x = match async_op1().poll(cx) {
                        .Ready(v) => v,
                        .Pending => return .Pending,
                    }
                    *self = .State1 { x }
                }
                .State1 { x } => {
                    let y = match async_op2().poll(cx) {
                        .Ready(v) => v,
                        .Pending => return .Pending,
                    }
                    *self = .State2 { x: *x, y }
                }
                .State2 { x, y } => {
                    return .Ready(x + y)
                }
                .Done => panic("polled after completion"),
            }
        }
    }
}

3. 并发组合

join (并行等待)

dast
async fn fetch_all() -> (Data1, Data2) {
    let (a, b) = join(
        fetch_data("url1"),
        fetch_data("url2")
    ).await
    return (a, b)
}

// 实现
async fn join[F1: Future, F2: Future](
    f1: F1,
    f2: F2
) -> (F1.Output, F2.Output) {
    // 同时 poll 两个 future
}

select (竞争等待)

dast
async fn race() -> Data {
    select! {
        data = fetch_fast() => data,
        data = fetch_slow() => data,
        timeout = sleep(Duration.seconds(5)) => {
            return default_data()
        }
    }
}

4. 取消语义

方案 A: Drop = 取消 (Rust 风格)

dast
async fn operation() {
    let fut = long_running_task()
    // drop(fut) 自动取消
}

优点: 简单、自动 缺点: 无法区分正常完成和取消

方案 B: 显式取消

dast
async fn operation() {
    let handle = spawn(long_running_task())
    handle.cancel()  // 显式取消
}

优点: 明确 缺点: 需要手动管理

建议: 混合方案

dast
// Drop 自动取消(默认)
{
    let fut = task()
}  // 自动取消

// 显式取消(需要时)
let handle = spawn(task())
handle.cancel()

5. 结构化并发

Scope (作用域并发)

dast
async fn parallel_work() {
    scope(|s| {
        s.spawn(async { task1().await })
        s.spawn(async { task2().await })
        s.spawn(async { task3().await })
    }).await
    // 所有任务完成后才继续
}

Nursery (托儿所模式)

dast
async fn supervised() {
    let nursery = Nursery.new()

    nursery.spawn(async { worker1().await })
    nursery.spawn(async { worker2().await })

    // 等待所有任务
    nursery.wait_all().await

    // 或取消所有
    nursery.cancel_all()
}

6. 运行时设计

单线程运行时

dast
fn main() {
    let rt = Runtime.new_single_thread()
    rt.block_on(async {
        main_async().await
    })
}

多线程运行时

dast
fn main() {
    let rt = Runtime.new_multi_thread()
        .worker_threads(4)
        .build()

    rt.block_on(async {
        main_async().await
    })
}

无运行时 (嵌入式)

dast
fn main() {
    let mut fut = main_async()
    let waker = noop_waker()
    let mut cx = Context { waker: &waker }

    loop {
        match fut.poll(&mut cx) {
            .Ready(v) => break v,
            .Pending => {
                // 等待事件
                wait_for_events()
            }
        }
    }
}

7. 与其他语言对比

特性JavaScriptGoRustDast
模型Push (Promise)CSP (goroutine)Pull (Future)Pull (Future)
语法async/awaitgo/chanasync/awaitasync/await
零成本
取消AbortControllercontextDropDrop + 显式
结构化并发⚠️ 第三方

8. 待确认问题

  1. Stream trait - 异步迭代器?
  2. AsyncRead/AsyncWrite - 异步 I/O trait?
  3. Pin - 是否需要?如何简化?
  4. Send 约束 - 跨线程 Future 的要求?

建议

特性决策
模型Pull (Rust 风格)
取消Drop + 显式
结构化并发✅ 内置 scope
运行时可选(单线程/多线程/无)
Pin简化版(结合 @pinned)

Released under the MIT License.