为什么不为包含 Arc 的结构实现 Send? [英] Why isnt Send implemented for a struct containing Arc?

查看:42
本文介绍了为什么不为包含 Arc 的结构实现 Send?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 一个板条箱与Postgres 只需手动编写 sql 查询(Diesel 似乎是我的简单案例),并且在对数据库客户端的多线程访问方面陷入困境.代码如下:

I'm using a crate to interact with Postgres with simply writing sql queries by hands (Diesel seems for my simple case) and got stuck about the multithreaded access to the database client. Here is the code:

use postgres::Client;

pub struct Database{
    connection: Arc<Client>
}

impl Database {
    pub fn from_config(url: &str) -> Database {
        //...
    }
}

fn main() {
    let url: String = //...
    let db = db::Database::from_config(&url);
    let db_ref = Arc::new(db);
    consume(future(Arc::clone(&db_ref))); // <------------------- compile error
}

async fn future(db_ref: Arc<db::Database>){ }

fn consume<F>(f: F)
where F: Send{ }

postgres::客户端定义为

/// A synchronous PostgreSQL client.
pub struct Client {
    connection: Connection,
    client: tokio_postgres::Client,
}

在编译这段代码时,我得到了一些疯狂的错误信息:

When compiling this code the compile I got somewhat crazy error message:

error[E0277]: `(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)` cannot be shared between threads safely
  --> src/main.rs:17:5
   |
17 |     consume(future(Arc::clone(&db_ref)));
   |     ^^^^^^^ `(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)` cannot be shared between threads safely
...
24 | fn consume<F>(f: F)
   |    ------- required by a bound in this
25 | where F: Send{ }
   |          ---- required by this bound in `consume`
   |
   = help: the trait `std::marker::Sync` is not implemented for `(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)`
   = note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)>`
   = note: required because it appears within the type `std::boxed::Box<(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)>`
   = note: required because it appears within the type `std::pin::Pin<std::boxed::Box<(dyn futures_core::stream::Stream<Item = std::result::Result<tokio_postgres::AsyncMessage, tokio_postgres::error::Error>> + std::marker::Send + 'static)>>`
   = note: required because it appears within the type `postgres::connection::Connection`
   = note: required because it appears within the type `postgres::client::Client`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<postgres::client::Client>`
   = note: required because it appears within the type `db::Database`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<db::Database>`
   = note: required because it appears within the type `[static generator@src/main.rs:22:43: 22:46 db_ref:std::sync::Arc<db::Database> {}]`
   = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@src/main.rs:22:43: 22:46 db_ref:std::sync::Arc<db::Database> {}]>`
   = note: required because it appears within the type `impl core::future::future::Future`
   = note: required because it appears within the type `impl core::future::future::Future`

这似乎意味着 Database 没有实现 Send.有没有办法实现Send?也许应该使用 Mutex 或其他东西来代替 Arc?

Which seems to mean that Database does not implement Send. Is there a way to make implement Send? Maybe Mutex or something else should be used instead of Arc?

UPD:

pub struct Database{
    connection: Mutex<Client>
}

使错误消失,但完全不清楚为什么...

makes the error disappear, but it is completely unclear why...

推荐答案

Arc 允许多个线程同时访问同一个值.Sync trait 用于验证访问不会导致内存不安全,因此 Arc 需要它.

Arc<T> allows multiple threads to access the same value at the same time. The Sync trait is what verifies that the access will not cause memory unsafety, hence why Arc requires it.

另一方面,Mutex通过锁定控制对T的访问,因此只有一个线程可以在同一时间访问T时间(从某种意义上说,将它发送"到拥有锁的线程).所以 MutexSync,即使 T 不是(尽管它仍然必须是 Send).

On the other hand, Mutex<T> controls access to T via locking, so that only one thread may access T at a time (in a sense, 'sending' it to the thread that has the lock). So Mutex<T> is Sync even if T is not (though it still must be Send).

然而,Mutex 本身并没有用,因为无论如何只有一个线程可以访问互斥锁.您通常将它与共享所有权的方式(即 Arc)结合起来,以允许多个线程访问互斥锁.

However Mutex<T> on its own isn't useful since only one thread will have access to the mutex anyway. You usually combine it with a way of sharing ownership (i.e. Arc) to allow multiple threads to have access the mutex.

这篇关于为什么不为包含 Arc 的结构实现 Send?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆