Rust-在多个worker之间共享结构中哈希集的最佳方法

问题描述 投票:0回答:1

我对Rust还是很陌生,我试图将我制作的Go Web搜寻器移植到Rust。在Go中,我创建了一个哈希图,供多个工作人员使用(并共享)(执行产生相同功能的例程)。使用Mutexes可以轻松解决该问题,但我无法掌握如何在Rust中执行相同的操作。

Crawler结构为:

struct Crawler {
    client: reqwest::Client,
    target: String,
    visited: Arc<Mutex<HashSet<String>>>,
    queue: Arc<Mutex<Queue<String>>>,
    base_url: String,
    fetch_any_domain: bool,
    workers: u8,
}

在履带的impl中,我添加了运行功能:

   fn run(&self) {
        {
            match self
                .queue
                .lock()
                .unwrap()
                .add(self.convert_link_to_abs(self.target.as_str()))
            {
                Err(e) => println!("{}", e),
                _ => (),
            }
        }

        while self.queue.lock().unwrap().size() > 0 {
            match self.queue.lock().unwrap().remove() {
                Ok(link) => match self.fetch(link.as_str()) {
                    Ok(content) => match self.get_links(content) {
                        Ok(()) => println!("added new links"),
                        Err(e) => println!("{}", e),
                    },
                    Err(e) => println!("{}", e),
                },
                Err(e) => println!("{}", e),
            }
        }
    }

而且我正尝试同时使用类似这样的名称:

        let mut threads = vec![];
        let c = Arc::new(Mutex::new(crawler));
        for _i in 0..workers {
            let cc = c.clone();
            threads.push(thread::spawn(move || {
                let guard = cc.lock().unwrap();
                guard.run();
            }));
        }

        for t in threads {
            let _ = t.join();
        }

代码以某种方式运行,但是它在不进行任何处理的情况下立即卡住了。我敢肯定,我只需要习惯Rust的方法,但是有人可以建议实现多线程爬虫的最佳方法是什么吗?

非常感谢

multithreading rust web-crawler spawn
1个回答
0
投票

问题不在于HashSet,而在于队列。如果您用标准库中的Vec替换了外部包装箱中的Queue,并拆分了一些语句,它将很好地工作。

fn run(&self) {
        {
            self.queue
                .lock()
                .unwrap()
                .push(self.convert_link_to_abs(self.target.as_str()))
        }

        while self.queue.lock().unwrap().len() > 0 {
            let x = self.queue.lock().unwrap().pop();
            match x {
                Some(link) => match self.fetch(&link) {
                    Ok(content) => match self.get_links(content) {
                        Ok(()) => println!("added new links"),
                        Err(e) => println!("{}", e),
                    },
                    Err(e) => println!("{}", e),
                },
                _ => {}
            }
        }
    }

最大的变化是我从match语句之外的队列中弹出。我认为如果比赛中有整个.lock().unwrap().pop()语句,则将为比赛块的整个内容持有该锁。

但是,如果您对所使用的队列箱进行同样的操作,我不确定为什么它不起作用。我也是Rust的初学者,所以其中一些我仍然不清楚。

我对您的代码所做的更改可以在这里看到:https://pastebin.com/ZrXrsgzf。我对此进行了测试,并且它可以运行(至少它超过了最初卡住的位置)。

我最近还在Rust中实现了一个Web搜寻器,并撰写了有关它的文章here

© www.soinside.com 2019 - 2024. All rights reserved.