Skip to content

Instantly share code, notes, and snippets.

@arkbriar
Created August 26, 2021 08:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arkbriar/39b30ac4a882277372dacbb85eb6cdd2 to your computer and use it in GitHub Desktop.
Save arkbriar/39b30ac4a882277372dacbb85eb6cdd2 to your computer and use it in GitHub Desktop.
About rust's async scope

假设 tokio 存在下面这种 scope

// mod task
async fn scope<'env, R>(f: Future<'env, Output=R>) -> R;

意味着可以写出

async fn parent_fut() {
    // lifetime: 'parent_fut
    let x = 1;
    let x_ref = &x;

    task::scope(async {
        // 这个 Future 绑定了 'parent_fut 的 scope,
        // 所以它的运行一定要保证 'parent_fut 还活着
        println!(x_ref);
    }).await;

    // 这么写确实保证了,因为这种写法 future 不会有 cancel
}

// 但假设

async fn parent_fut() {
    // lifetime: 'parent_fut
    let x = 1;
    let x_ref = &x;

    let sleep = tokio::sleep(1);

    scoped_fut = task::scope(async {
        // 这个 Future 绑定了 'parent_fut 的 scope,
        // 所以它的运行一定要保证 'parent_fut 还活着

        // 而这里 spawn 另一个 fut,同样绑定了 scope
        // P.S. 这里如果保留 spawn 原有的 'static 绑定就失去了各种意义,
        // 意味着在 scoped future 里只能干单线程持有 scope 的事情,
        // e.g. some(x_ref).await but not concurrently
        // 所以那个 proposal 里提出在这里要自动绑定 parent scope.
        let outlive_fut = tokio::spawn(async {
            println!(x_ref);
        })
        outlive_fut.await.unwrap();
    }).await;

    select! {
        sleep => {
            // 如果这里先结束,意味着 scoped_fut 不会再继续推进了
            // 而 scoped_fut 不会推进意味着 outlive_fut 可能在 parent_fut 
            // 执行结束完,还在继续执行
            // 
            // parent_fut 执行结束意味着 Drop 立刻就会发生,那么 'parent_fut 
            // 就挂了,outlive_fut 的执行一定会出问题
            //
            // 为了避免这个问题,parent_fut 结束前一定要 cancel outlive_fut, 而 outlive_fut
            // 跟 parent_fut 其实并没有 scope 上的直接关系,aka. 合理的方案是:
            //   parent_fut 一定要 cancel scoped_fut, scoped_fut 去 cancel outlive_fut
            //
            // 这个也是原 proposal 里的,scoped future 一定要 cancel (either force or gratefully)
            // 它里面的所有还没执行完的 future。
            //
            // 所以要实现这个 cancel,怎么实现?目前只有 Drop,假设用 Drop 能实现 cancel。
            // Attention:
            //   1. Drop 是立即执行,且占用当前线程。
            //   2. Future 无法被立即 cancel(可能在运行中),一定存在等待的情况。
            // => Drop Cancel 一定存在等待,且阻塞
            // 假设 Drop 实现了一个 blocking thread 并等待里面的 future 结束,确实就实现了,但意味着这个线程就被吃掉了,而
            // 单线程运行时此时就意味着其他所有的 future 无法推进,死锁。多线程运行时虽然可以缓解这个问题,
            // 但是并不能解决 (e.g. 所有 thread 都 block on cancel)。
            //
            // 所以一定要 Async Cancel。
            // 没想明白怎么实现。
            return;
        }
        scoped_fut => {
            return;
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment