Asynchronous 是否使用async/await实现静态?

Asynchronous 是否使用async/await实现静态?,asynchronous,rust,Asynchronous,Rust,阿萨拉穆·阿莱库姆 我是个新手。我正在使用mongodb和异步运行时(tokio) 我想全局初始化mongo客户端,所以我使用了一个名为的板条箱。问题是mongodb异步连接,而现在lazy\u static不支持async关键字 使用mongodb::Client; 异步的{ 让client=client::with_uri_str(&env_var(“MONGO_URL”)).wait.unwrap(); } 那么如何全局初始化客户机对象呢 相关的: 如果使用新的运行时,并且首先在现有

阿萨拉穆·阿莱库姆

我是个新手。我正在使用mongodb和异步运行时(tokio)
我想全局初始化mongo客户端,所以我使用了一个名为的板条箱。问题是mongodb异步连接,而现在lazy\u static不支持
async
关键字

使用mongodb::Client;
异步的{
让client=client::with_uri_str(&env_var(“MONGO_URL”)).wait.unwrap();
}
那么如何全局初始化
客户机
对象呢

相关的:



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

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");
}
您将看到提到的错误:

线程“main”处于恐慌状态,无法从运行时内启动运行时。发生这种情况的原因是,当线程用于驱动异步任务时,函数(如“block_on”)试图阻止当前线程。C:\Users\kmdreko\.cargo\registry\src\github.com-1ec6299db9ec823\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");
}

这假设客户端的所有或几乎所有使用都是在异步上下文中进行的。

如果初始化时使用tokio提供的
block_on
函数而不是
wait
可以阻止,那么等待结果就会完成任务。你链接的StackOverflow Q&A有两个建议:要么
block_on
或者使用
OnceCell
。为什么答案不充分?据我所知,您正在寻找的是一种类似于
lazy\u static的
OnceCell
包装器,但它是用
异步
块而不是闭包初始化的。然而,在这种情况下,似乎
mongodb
库的编码很差,而
with_uri_str
方法实际上不需要是
异步的,所以我只需要使用
block_on
。多亏了您的时间,但使用您的方法创建新问题,我仍然在寻找答案,最低限度是@Coder-256,@Aiden4,@kmdreko,我试过
OnceCell
futures::executor::block_on
tokio::runtime::runtime::new
等等,它们都会产生新的问题,比如线程“tokio runtime worker”恐慌于“无法从另一个executor内部执行
LocalPool
executor:enterror”等等。。。
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");
}