Exc*_*ser 18 multithreading mutex rust
我正在调用异步实现的方法:
let mut safebrowsing: MutexGuard<Safebrowsing> = self.safebrowsing.lock().unwrap();
safebrowsing.is_safe(input: &message.content).await;
Run Code Online (Sandbox Code Playgroud)
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")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
但不幸的是,通过异步调用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
Run Code Online (Sandbox Code Playgroud)
我已经尝试将Send -Trait 实现到我的 Safebrowsing-Struct,但这也不起作用。我需要做些什么才能使其正常工作吗?因为我不知道为什么会出现
小智 16
使用您正在使用的异步运行时的互斥体实现。
前
use std::sync::Mutex; // stdlib
let m = Mutex::new(...);
let v = m.lock().unwrap();
Run Code Online (Sandbox Code Playgroud)
后
use tokio::sync::Mutex; // tokio async runtime
let m = Mutex::new(...); // the same!
let v = m.lock().await;
Run Code Online (Sandbox Code Playgroud)
但为什么?
粗略地说,本机互斥体强制将锁保留在同一个线程中,但异步运行时不理解它。
如果您的锁不与 交叉async
,那么您可以使用 stdlib 中的互斥锁(它可以更快)。
请参阅tokio文档中的讨论。
rod*_*igo 14
这个错误的关键是MutexGuard<T>
不是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")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您需要Mutex
在函数中锁定后者,请小心竞争!它可能已被其他线程修改,也许这input
不再是问题了。