rust - 可中止 : Dangling Futures?

标签 rust async-await rust-tokio

我正在使用Abortable crate 来暂停 Future 的执行。假设我有一个可中止的 future ,其中异步函数本身正在等待其他异步函数。我的问题是,如果我中止根 Future,子 Future 会同时立即中止,还是会悬空?

我阅读了 Abortable 的源代码,特别是 try_poll 的代码:

fn try_poll<I>(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        poll: impl Fn(Pin<&mut T>, &mut Context<'_>) -> Poll<I>,
    ) -> Poll<Result<I, Aborted>> {
        // Check if the task has been aborted
        if self.is_aborted() {
            return Poll::Ready(Err(Aborted));
        }

        // attempt to complete the task
        if let Poll::Ready(x) = poll(self.as_mut().project().task, cx) {
            return Poll::Ready(Ok(x));
        }

        // Register to receive a wakeup if the task is aborted in the future
        self.inner.waker.register(cx.waker());

        // Check to see if the task was aborted between the first check and
        // registration.
        // Checking with `is_aborted` which uses `Relaxed` is sufficient because
        // `register` introduces an `AcqRel` barrier.
        if self.is_aborted() {
            return Poll::Ready(Err(Aborted));
        }

        Poll::Pending
    }

我的理解是,一旦abort被调用,它就会传播到下游Futures,从某种意义上说,当根Future被中止时,它将停止轮询其子Future(因为Poll::Ready(Err(Aborted)) 将被返回),这将依次停止轮询其子级。如果这个推理是正确的,那么调用 abort 的效果是立即的。
另一个论点是,如果 Future 是基于拉动的,则应首先调用根节点,然后传播到子任务,直到调用并中止叶节点(然后返回到根)。这意味着在调用 abort 方法和叶子 Future 实际停止轮询之间存在延迟。可能相关,但是这个blogpost提到悬空任务,我担心情况就是如此。
例如,这是我写的一个玩具示例:

use futures::future::{AbortHandle, Abortable};
use tokio::{time::sleep};
use std::{time::{Duration, SystemTime}};

/*
 *       main
 *         \
 *       child
 *         | \
 *        |   \
 *    leaf1   leaf2
 */
 

async fn leaf2() {
    println!("This will not be printed")
}

async fn leaf1(s: String) {
    println!("[{:?}] ====== in a ======", SystemTime::now());
    for i in 0..100000 {
        println!("[{:?}] before sleep i is {}", SystemTime::now(), i);
        sleep(Duration::from_millis(1)).await;
        println!("[{:?}] {}! i is {}", SystemTime::now(), s.clone(), i);
    }
}
 
async fn child(s: String) {
    println!("[{:?}] ====== in child ======", SystemTime::now());
    leaf1(s.clone()).await;
    leaf2().await
}
 
#[tokio::main]
async fn main() {
    let (abort_handle, abort_registration) = AbortHandle::new_pair();
    let result_fut = Abortable::new(child(String::from("Hello")), abort_registration);

    tokio::spawn(async move {
        println!("{:?} ^^^^^ before sleep ^^^^^", SystemTime::now());
        sleep(Duration::from_millis(100)).await;
        println!("{:?} ^^^^^ after sleep, about to abort ^^^^^", SystemTime::now());
        abort_handle.abort();
        println!("{:?} ***** operation aborted *****", SystemTime::now());
    });

    println!("{:?} ====== before main sleeps ======", SystemTime::now());
    sleep(Duration::from_millis(5)).await;
    println!("{:?} ====== after main wakes up from sleep and now getting results \
            ======", SystemTime::now());
    result_fut.await.unwrap();
}

Rust playground
我个人更倾向于第一个论点,即根的中止和叶子的中止之间没有延迟,因为叶子不需要知道它需要中止(叶子仅在根告诉它时才拉动)。上面的示例打印子进程执行的时间和根进程中止的时间。 child 的执行总是在 root 被中止之前,但是我不确定这是否可以证明我的第一个论点是正确的,所以我想知道你们的想法!

最佳答案

是的,因为 future 需要轮询才能执行,但如果中止则不会被轮询,所以子 future 也不会被轮询,因此执行将立即停止。

当然,只有在到达下一个屈服点后执行才会停止,并且使用 tokio::spawn() 生成的任务不会停止。

关于rust - 可中止 : Dangling Futures?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75211452/

相关文章:

python - 如何在 Alpine docker镜像中为orjson python库设置rust工具链?

debugging - 如何创建用于调试的 Rust 函数或宏,以便在发布版本中进行优化?

Rust diesel orm查询

asynchronous - 如何从 Tokio 的非主线程运行异步任务?

rust - 如何停止超 HTTP Web 服务器并返回错误?

rust - tokio::net::TcpStream是如何实现tokio::prelude::Stream的?

rust - 为什么我不能 `.iter()` 字符串切片?

c# - async 和await 关键字适用于什么?

javascript - async await with promises 然后需要阻止

c# - 如何使 UdpClient.ReceiveAsync() 可取消?