我一直在尝试从postgres迁移到tokio_postgres,但是与一些异步技术做了斗争。
use scraper::Html;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::task;
struct Url {}
impl Url {
fn scrapped_home(&self, symbol: String) -> Html {
let url = format!(
"https://finance.yahoo.com/quote/{}?p={}&.tsrc=fin-srch", symbol, symbol
);
let response = reqwest::blocking::get(url).unwrap().text().unwrap();
scraper::Html::parse_document(&response)
}
}
#[derive(Clone)]
struct StockData {
symbol: String,
}
#[tokio::main]
async fn main() {
let stock_data = StockData { symbol: "".to_string() };
let url = Url {};
let mut uri_test: Arc<Mutex<Html>> = Arc::new(Mutex::from(url.scrapped_home(stock_data.clone().symbol)));
let mut uri_test_closure = Arc::clone(&uri_test);
let uri = task::spawn_blocking(|| {
uri_test_closure.lock()
});
}不加互斥物
url.scrapped_home(stock_data.clone().symbol)),在不允许阻塞的上下文中,我会得到运行时不能下降的错误,所以我将其放入spawn_blocking中。然后,我得到一个错误,即单元格不能在线程之间安全地共享。据我所知,这是因为细胞不是同步的。然后我把它包裹在一个互斥装置里。另一方面,抛出的单元格不能在线程之间安全地共享。
那么,这是因为它包含了对单元格的引用,因此内存不安全吗?如果是这样的话,我需要为Html实现同步吗?又是如何做到的?
Html是从刮板箱。
更新:
对不起,这是错误。
error: future cannot be sent between threads safely
--> src/database/queries.rs:141:40
|
141 | let uri = task::spawn_blocking(|| {
| ________________________________________^
142 | | uri_test_closure.lock()
143 | | });
| |_________^ future is not `Send`
|
= help: within `tendril::tendril::NonAtomic`, the trait `Sync` is not implemented for `Cell<usize>`
note: required by a bound in `spawn_blocking`
--> /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.20.1/src/task/blocking.rs:195:12
|
195 | R: Send + 'static,
| ^^^^ required by this bound in `spawn_blocking`更新:
根据请求添加Cargo.toml:
[package]
name = "reprod"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = { version = "0.11", features = ["json", "blocking"] }
tokio = { version = "1", features = ["full"] }
tokio-postgres = "0"
scraper = "0.12.0"更新:添加原始同步代码:
fn main() {
let stock_data = StockData { symbol: "".to_string() };
let url = Url {};
url.scrapped_home(stock_data.clone().symbol);
}更新:多亏了凯文,我才能让它开始工作。正如他指出的,Html既不是Send,也不是Sync。这个铁锈朗博士的一部分帮助我理解消息传递是如何工作的。
pub fn scrapped_home(&self, symbol: String) -> Html {
let (tx, rx) = mpsc::channel();
let url = format!(
"https://finance.yahoo.com/quote/{}?p={}&.tsrc=fin-srch", symbol, symbol
);
thread::spawn(move || {
let val = reqwest::blocking::get(url).unwrap().text().unwrap();
tx.send(val).unwrap();
});
scraper::Html::parse_document(&rx.recv().unwrap())
}之后,我有了某种顿悟,并让它与托基奥一起工作,也没有消息传递。
pub async fn scrapped_home(&self, symbol: String) -> Html {
let url = format!(
"https://finance.yahoo.com/quote/{}?p={}&.tsrc=fin-srch", symbol, symbol
);
let response = task::spawn_blocking(move || {
reqwest::blocking::get(url).unwrap().text().unwrap()
}).await.unwrap();
scraper::Html::parse_document(&response)
}我希望这能帮上忙。
发布于 2022-10-27 14:24:46
这一点现在更清楚地说明了这一点:您正在尝试跨线程边界返回一个tokio::sync::MutexGuard。当你说这是:
let mut uri_test: Arc<Mutex<Html>> = Arc::new(Mutex::from(url.scrapped_home(stock_data.clone().symbol)));
let mut uri_test_closure = Arc::clone(&uri_test);
let uri = task::spawn_blocking(|| {
uri_test_closure.lock()
});uri_test_closure.lock()调用(tokio::sync::Mutex::lock())没有分号,这意味着它返回的对象是调用的结果。但是不能跨线程边界返回MutexGuard。
我建议您阅读链接lock()调用,以及blocking_lock()之类的内容。
我不确定你在这里打电话给task::spawn_blocking有什么意义。如果您试图说明某物的用例,这是不可能的。
编辑:
问题更深。Html既是!Send又是!Sync,这意味着您甚至不能将其封装在Arc<Mutex<Html>>或Arc<Mutex<Optional<Html>>>或其他任何东西中。您需要以另一种方式从另一个线程获取数据,而不是作为“整体”对象。有关更详细的信息,请参见生锈用户论坛上的这个职位。但是您要包装的东西必须是Send,而这个结构显然不是。
因此,如果类型为Send和!Sync,则可以将其包装为Mutex和Arc。但是如果是!Send,则需要使用消息传递或其他同步机制。
https://stackoverflow.com/questions/74210584
复制相似问题