生锈 "future cannot be sent between threads safely"

Rust "future cannot be sent between threads safely"

我正在调用异步实现的方法:

let mut safebrowsing: MutexGuard<Safebrowsing> = self.safebrowsing.lock().unwrap();
safebrowsing.is_safe(input: &message.content).await;

is_safe-方法:

pub async fn is_safe(&mut self, input: &str) {
    let links = self.finder.links(input);

    for link in links {
        match reqwest::get("url").await {
            Ok(response) => {
                println!(
                    "{}",
                    response.text().await.expect("response has no content")
                );
            }
            Err(_) => {
                println!("Unable to get safebrowsing-response")
            }
        }
    }
}

但不幸的是,通过异步调用 is_safe-方法,编译器告诉我线程无法安全发送。错误是关于:

future cannot be sent between threads safely
within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, Safebrowsing>`
required for the cast to the object type `dyn std::future::Future<Output = ()> + std::marker::Send`

handler.rs(31, 9): future is not `Send` as this value is used across an await
           ^-- safebrowsing.is_safe(input: &message.content).await;
---

future cannot be sent between threads safely
the trait `std::marker::Send` is not implemented for `(dyn for<'r> Fn(&'r [u8]) -> Option<usize> + 'static)`
required for the cast to the object type `dyn std::future::Future<Output = ()> + std::marker::Send`

safebrowsing.rs(22, 19): future is not `Send` as this value is used across an await
               ^-- match reqwest::get("url").await

我已经尝试将 Send-Trait 实现到我的 Safebrowsing-Struct,但这也不起作用。 我需要做些什么才能使其正常工作吗?因为我不知道为什么会出现这种情况

这个错误的关键在于MutexGuard<T> is not Send。这意味着您正在尝试在互斥量被锁定时执行 await,这通常是一个坏主意,如果您考虑一下:await 原则上可能会无限期地等待,但是通过等待只要持有互斥锁,任何其他试图锁定互斥锁的线程都会无限期地阻塞(当然,除非你设置了超时)。

因此,根据经验,您永远不应该在锁定互斥锁的情况下睡觉。例如,您的代码可以重写为(完全未经测试):

pub async fn is_safe(this: &Mutex<Safebrowsing>, input: &str) {
    //lock, find, unlock
    let links = this.lock().unwrap().finder.links(input);
    //now we can await safely
    for link in links {
        match reqwest::get("url").await {
            Ok(response) => {
                println!(
                    "{}",
                    response.text().await.expect("response has no content")
                );
            }
            Err(_) => {
                println!("Unable to get safebrowsing-response")
            }
        }
    }
}

如果您稍后需要在函数中锁定 Mutex,请注意争用!它可能已被其他线程修改,也许 input 不再是一个东西。