1个不稳定版本

0.1.0 2024年3月17日

#27 in #spawn

自定义许可

8KB
102

寄生任务

寄生任务是那些不会被任何执行器调度的任务,而是直接在调用唤醒者的线程上立即派发。

这使得异步结果可以就地处理,无需在单独的线程上排队进行后续操作。这在响应延迟是一个关键问题的场合很有用,比如在高频交易应用中。

用法

只需使用 ptask::spawn 运行一个寄生任务,它将在当前线程上立即派发,直到它 await 一个尚未完成的未来,通常是从异步通道接收。

请注意,任务内部使用 Arc 进行引用计数,因为等待的异步操作必须持有保持任务活动的唤醒者。因此,发送者可以被视为正在等待接收者的任务的拥有者。请注意,如果有多个ptask持有彼此的发送者的引用,则某些发送者必须用 Weak 引用包装起来,以避免循环引用。

use futures::{channel::mpsc, StreamExt};
use std::sync::{
    atomic::{AtomicUsize, Ordering},
    Arc,
};

// This demo shows how it works on a single thread.
#[test]
fn demo() {
    let (tx, mut rx) = mpsc::unbounded();
    let result = Arc::new(AtomicUsize::new(0));

    // Spawn a ptask that runs immediately until the first `await`.
    // Then the `await`ed channel holds the reference to the task.
    ptask::spawn({
        let result = result.clone();
        async move {
            while let Some(i) = rx.next().await {
                result.fetch_add(i, Ordering::Relaxed);
            }
            result.fetch_add(10, Ordering::Relaxed);
        }
    });

    for i in 0..10 {
        // Sending to the channel makes the ptask resumes running until the next `await`.
        tx.unbounded_send(i).unwrap();
        assert_ne!(result.load(Ordering::Relaxed), 55);
    }

    // Drop the sender so that the ptask breaks out of the loop.
    drop(tx);

    assert_eq!(result.load(Ordering::Relaxed), 55);
}

功能

此crate支持 no_std 但需要可用的 alloc crate。

可选功能

默认情况下,此crate将所有函数标记为 #[inline(always)],这确保了在需要的情况下有极好的性能。但是,如果代码大小仍然是关注点,您可以通过禁用默认功能来禁用此行为,这与普通crate一样进行内联。

依赖关系

~0.4–5.5MB
~11K SLoC