为什么连接池会克隆到这里?

问题描述

在此代码示例中,来自 Github page of r2d2

fn main() {
    let manager = r2d2_foodb::FooConnectionManager::new("localhost:1234");
    let pool = r2d2::Pool::builder()
        .max_size(15)
        .build(manager)
        .unwrap();

    for _ in 0..20 {
        let pool = pool.clone();
        thread::spawn(move || {
            let conn = pool.get().unwrap();
        })
    }
}

为什么要在循环中克隆 Pool 结构?

解决方法

这是因为循环内产生的线程需要获得 pool 的所有权,因为每个线程的运行时间可能超过 main。如果 pool 在线程仍在运行时退出,则从线程内部引用 main 拥有的 main 可能会导致引用已被销毁的值。

获得 pool 的所有权要求您在每次循环执行时克隆它,因此每个线程都有自己的副本。

在内部,Pool 是一个 std::sync::Arc,而 Clone 实现只是简单地克隆了 Arc。也就是说,Pool 的每个克隆只是一个递增的引用计数。随着线程的创建,引用计数会增加。当线程完成时,它们通过删除 Pool 来减少引用计数,当引用计数达到零时破坏底层连接。