#thread-local #future #thread #async #local-storage #atexit

nolocal-block-on

futures_lite::future::block_on 不使用线程局部变量的版本

2 个稳定版本

1.0.1 2024 年 8 月 5 日

#401异步

Download history 167/week @ 2024-07-31 52/week @ 2024-08-07

219 每月下载量
async-blocking-stdio 中使用

MPL-2.0 许可证

10KB

nolocal-block-on

这是 futures_lite::future::block_on 的版本,它不使用任何线程局部变量。这是一个非常专业的 crate,用于程序的特定部分(例如在 libc::atexit 回调中,或者主程序前后发生的事情)在这些地方线程局部存储将无法工作。

但是,如果你的未来本身使用线程局部存储,那么你很不幸(或者需要更改你正在使用的未来的实现)。

除了上述特定情况之外,你几乎肯定需要正常的 futures_lite::future::block_on

示例

调用此 crate 提供的函数的方法与 futures-lite 版本 相同

let val = nolocal_block_on::block_on(async {
    1 + 2
});

assert_eq!(val, 3);

但是,futures-lite 版本 在线程局部存储无法工作的(罕见)地方无法工作 - 例如,在主 rust 运行时关闭后运行。为了说明这一点,我们通过 libc::atexit 来演示。

以下使用 futures_lite::future::block_on 的代码可能会因为实现中使用了线程局部变量而引发 panic - 并且特别是在涉及多个线程(如 blocking::Unblock)时,它将一致地引发 panic

use futures_lite::{future::block_on, io::AsyncWriteExt};
use async_lock::Mutex;
use std::{sync::LazyLock, io::{Stdout, self}};
use blocking::Unblock;

static STDOUT: LazyLock<Mutex<Unblock<Stdout>>> = LazyLock::new(|| {
    Mutex::new(Unblock::new(io::stdout()))
});

block_on(async { STDOUT.lock().await.write(b"hello program\n").await });

extern "C" fn cleanup() {
    block_on(async {
        let mut locked_stdout = STDOUT.lock().await;
        locked_stdout.write(b"goodbye program!\n").await;
        locked_stdout.flush().await;
    });
}

unsafe { libc::atexit(cleanup); }

然而,以下使用 nolocal_block_on::block_on 的代码不会引发恐慌,因为实现没有使用任何线程局部变量(对于非平凡的未来,你可能需要检查它们在实现中是否使用线程局部变量)

use nolocal_block_on::block_on;
use futures_lite::io::AsyncWriteExt;
use async_lock::Mutex;
use std::{sync::LazyLock, io::{Stdout, self}};
use blocking::Unblock;

static STDOUT: LazyLock<Mutex<Unblock<Stdout>>> = LazyLock::new(|| {
    Mutex::new(Unblock::new(io::stdout()))
});

block_on(async { STDOUT.lock().await.write(b"hello program\n").await });

extern "C" fn cleanup() {
    block_on(async {
        let mut locked_stdout = STDOUT.lock().await;
        locked_stdout.write(b"goodbye program!\n").await;
        locked_stdout.flush().await;
    });
}

unsafe { libc::atexit(cleanup); }

依赖项

约16KB