微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何通过异步任务获得 tokio_postgres::Client 的互斥锁的所有权?

如何解决如何通过异步任务获得 tokio_postgres::Client 的互斥锁的所有权?

我想创建一个返回 tokio_postgres 客户端的函数。但是,我找不到在异步任务(连接到数据库)中获取变量所有权(来自库 tokio_postgres数据库连接)的解决方案。

这是我的代码 (Playground):

use std::sync::{Arc,Mutex};
use tokio_postgres::tls::NoTlsstream;
use tokio_postgres::{Client,Connection,Error,NoTls,Socket};

#[tokio::main] // By default,tokio_postgres uses the tokio crate as its runtime.
async fn main() -> Result<(),Error> {
    let pg_client = create_pg_client("postgres://postgres:root@localhost:5432");
    // Use pg_client for the program
    Ok(())
}

//
// Creates a pg client
//
pub async fn create_pg_client(
    config: &str,) -> Result<Arc<Mutex<(Client,Connection<Socket,NoTlsstream>)>>,Error> {
    // Connect to the database.
    let mut connect_result = Arc::new(Mutex::new(tokio_postgres::connect(config,NoTls).await?));

    let connect_result_thread = connect_result.clone();
    // The connection object performs the actual communication with the database,// so spawn it off to run on its own.
    tokio::spawn(async move {
        let mut result = connect_result_thread.lock().unwrap();
        if let Err(e) = (&mut result.1).await {
            eprintln!("An error occured while trying to connect to the database");
        }
    });

    Ok(connect_result)
}

我的代码无法编译:

error: future cannot be sent between threads safely
   --> src\pg_client.rs:18:5
    |
18  |     tokio::spawn(async move {
    |     ^^^^^^^^^^^^ future created by async block is not `Send`
    | 
   ::: src\github.com-1ecc6299db9ec823\tokio-1.5.0\src\task\spawn.rs:129:21
    |
129 |         T: Future + Send + 'static,|                     ---- required by this bound in `tokio::spawn`
    |
    = help: within `impl Future`,the trait `Send` is not implemented for `std::sync::MutexGuard<'_,(Client,tokio_postgres::Connection<Socket,NoTlsstream>)>`
note: future is not `Send` as this value is used across an await
   --> src\pg_client.rs:20:25
    |
19  |         let mut result = connect_result_thread.lock().unwrap();
    |             ---------- has type `std::sync::MutexGuard<'_,NoTlsstream>)>` which is not `Send`
20  |         if let Err(e) = (*result).1.await {
    |                         ^^^^^^^^^^^^^^^^^ await occurs here,with `mut result` maybe used later
...
23  |     });
    |     - `mut result` is later dropped here

它表示不能安全地在线程之间发送未来。有没有可能实现我想要的?

使用的板条箱:

tokio = { version = "1.5.0",features = ["full"]}
tokio-postgres = "0.7.2"

解决方法

标准库 Mutex 旨在在单个线程的上下文中持有锁。由于任务可以由不同的线程拾取,跨 await 点的值必须为 Send。此外,即使它确实有效,在异步程序中使用阻塞互斥锁也是一个坏主意,因为获取互斥锁可能需要任意长的时间,在此期间其他任务无法在同一个执行器线程上运行。

您可以通过切换到 tokio's mutex 来解决这两个问题,该 Playground 的守卫是 Send,其 lock() 方法是异步的。例如,这会编译:

// Pick up an async aware Mutex
use tokio::sync::Mutex;

let connect_result = Arc::new(Mutex::new(tokio_postgres::connect(config,NoTls).await?));
let connect_result_thread = connect_result.clone();
tokio::spawn(async move {
    let mut result = connect_result_thread.lock().await;
    if let Err(e) = (&mut result.1).await {
        eprintln!("An error occured while trying to connect to the database: {}",e);
    }
});

Ok(connect_result)

Merge JavaScript objects in array with same key

尚不清楚的是这种设计的最终目标。如果连接位于互斥锁后面,则您可以有效地序列化从各种任务对它的访问。首先,这种连接可能不应该在任务之间共享。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?