rust 在Mutex之后无法在线程之间安全地发送future

wfsdck30  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(173)

我一直在尝试从postgres迁移到时雄_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中放入。然后我得到Cell不能在线程之间安全共享的错误。从我所能收集的来看,这是因为Cell不是“它的同步。然后我在互斥体中 Package 。另一方面,这会抛出Cell不能在线程之间安全共享"。
现在,这是因为它包含了对Cell的引用,因此不是内存安全的吗?如果是这样,我需要为Html实现Sync吗?如何实现?
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`

最新消息:
按要求添加货物:

[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);
}

更新:多亏了Kevin,我才能让它工作起来。正如他指出的Html既不是Send也不是Sync。这个part of the Rust lang doc帮助我理解了消息传递是如何工作的。

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)
        }

我希望这能帮助到一些人。

wkftcu5l

wkftcu5l1#

这一点现在更清楚地说明了:您试图跨越线程边界返回一个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>>>或其他类型的线程中。而不是作为一个“整体”的对象。更多的详细信息请参见rust用户论坛上的this post。但是无论你 Package 的是什么,* 必须 * 是Send,且该结构体显式为 not
因此,如果一个类型是Send!Sync,您可以 Package 在一个Mutex和一个Arc中,但是如果它是!Send,您就被束缚住了,需要使用消息传递或其他同步机制。

相关问题