首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Mutex之后,无法在线程之间安全地发送未来

在Mutex之后,无法在线程之间安全地发送未来
EN

Stack Overflow用户
提问于 2022-10-26 15:42:41
回答 1查看 116关注 0票数 0

我一直在尝试从postgres迁移到tokio_postgres,但是与一些异步技术做了斗争。

代码语言:javascript
复制
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()
    });
}

不加互斥物

代码语言:javascript
复制
url.scrapped_home(stock_data.clone().symbol)),

在不允许阻塞的上下文中,我会得到运行时不能下降的错误,所以我将其放入spawn_blocking中。然后,我得到一个错误,即单元格不能在线程之间安全地共享。据我所知,这是因为细胞不是同步的。然后我把它包裹在一个互斥装置里。另一方面,抛出的单元格不能在线程之间安全地共享。

那么,这是因为它包含了对单元格的引用,因此内存不安全吗?如果是这样的话,我需要为Html实现同步吗?又是如何做到的?

Html是从刮板箱。

更新:

对不起,这是错误。

代码语言:javascript
复制
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:

代码语言:javascript
复制
[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"

更新:添加原始同步代码:

代码语言:javascript
复制
fn main() {
    let stock_data = StockData { symbol: "".to_string() };
    let url = Url {};
    
    url.scrapped_home(stock_data.clone().symbol);
}

更新:多亏了凯文,我才能让它开始工作。正如他指出的,Html既不是Send,也不是Sync。这个铁锈朗博士的一部分帮助我理解消息传递是如何工作的。

代码语言:javascript
复制
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())
    }

之后,我有了某种顿悟,并让它与托基奥一起工作,也没有消息传递。

代码语言:javascript
复制
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)
        }

我希望这能帮上忙。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-27 14:24:46

这一点现在更清楚地说明了这一点:您正在尝试跨线程边界返回一个tokio::sync::MutexGuard。当你说这是:

代码语言:javascript
复制
    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,则可以将其包装为MutexArc。但是如果是!Send,则需要使用消息传递或其他同步机制。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74210584

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档