asynchronous - Rust lazy_static 与 async/await?

标签 asynchronous rust

我是 Rust 的新手。我正在将 mongodb 与异步运行时(tokio)一起使用。
我想全局初始化 mongo 客户端,所以我使用了一个名为 lazy_static 的 crate .问题是mongodb是异步连接的,现在lazy_static不支持async关键词...

use mongodb::Client;
async {
   let client = Client::with_uri_str(&env_var("MONGO_URL")).await.unwrap();
}
那么我如何初始化 client全局对象?
有关的:
Async/await support?

alternative to using 'await' with lazy_static! macro in rust?

最佳答案

如果您使用新的运行时并且首先在现有运行时的上下文中使用惰性静态,如下例所示:

use lazy_static::lazy_static;
use mongodb::Client;

lazy_static! {
    static ref CLIENT: Client = {
        tokio::runtime::Runtime::new().unwrap().block_on(async {
            let uri = std::env::var("MONGO_URL").unwrap();
            let client = Client::with_uri_str(&uri).await.unwrap();

            client
        })
    };
}

#[tokio::main]
async fn main() {
    let _db = CLIENT.database("local");
}
你会得到提到的错误:
thread 'main' panicked at 'Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.', C:\Users\kmdreko\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.6.1\src\runtime\enter.rs:39:9
您可以通过使用不同的运行时( futures vs tokio vs async-std )来规避这一点,但这并不理想,因为它仍然会阻止底层运行。

解决这个问题的一个相对直接的方法是不要尝试懒惰地去做并立即在 main 中初始化它。 .这样你就可以直接使用异步运行时而不必担心在其他地方需要一个:
use mongodb::Client;
use once_cell::sync::OnceCell;

static CLIENT: OnceCell<Client> = OnceCell::new();

#[tokio::main]
async fn main() {
    let uri = std::env::var("MONGO_URL").unwrap();
    let client = Client::with_uri_str(&uri).await.unwrap();
    CLIENT.set(client).unwrap();

    let _db = CLIENT.get().unwrap().database("local");
}
这可以通过 OnceCell 完成(如上所示)或类似 RwLock 的东西如有必要。

对于您要实现的目标,最直接的答案是使用 async_once crate,这使它使用接收器的运行时来驱动异步函数。
use async_once::AsyncOnce;
use lazy_static::lazy_static;
use mongodb::Client;

lazy_static! {
    static ref CLIENT: AsyncOnce<Client> = AsyncOnce::new(async {
        let uri = std::env::var("MONGO_URL").unwrap();
        let client = Client::with_uri_str(&uri).await.unwrap();

        client
    });
}

#[tokio::main]
async fn main() {
    let _db = CLIENT.get().await.database("local");
}
这假设客户端的所有或几乎所有使用都在异步上下文中。

关于asynchronous - Rust lazy_static 与 async/await?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67650879/

相关文章:

rust - 一次实现多个新类型的特征

rust - 如何在actix_web FromRequest特征实现中返回映射的将来? [复制]

rust - 如何避免对 libssl.so.10 和 libcrypto.so.10 的依赖

c# - 更新 Task 中的 UI 控件

mysql - NodeJS MySQL 将查询与多个模型查询的响应连接到一个 Controller 调用

c# - 等待大量任务

ios - Swift 闭包 [weak self] 和异步任务

javascript - 异步运行 AJAX 时的 doctype 标记为 "Unexpected end of input",但同步时则不然

pointers - Box,ref和&和*之间的理解和关系

vector - 有没有办法将 ChunkMut<T> 从 Vec::chunks_mut 转换为切片 &mut [T]?