首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Rust -在多个工作进程之间共享结构中的哈希集的最佳方式

Rust -在多个工作进程之间共享结构中的哈希集的最佳方式
EN

Stack Overflow用户
提问于 2020-02-07 05:05:51
回答 1查看 390关注 0票数 0

我是Rust的新手,我想把我制作的Go网络爬虫移植到Rust上。在Go中,我创建了一个供多个worker使用(和共享)的hashmap (go例程生成相同的函数)。使用Mutexes很容易解决这个问题,但我不能掌握如何在Rust中做同样的事情。

Crawler结构是:

代码语言:javascript
运行
复制
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中,我添加了运行函数:

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

我试着同时调用它,就像这样:

代码语言:javascript
运行
复制
        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方法,但是有人能建议一下实现多线程爬虫的最好方法是什么吗?

非常感谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-03-04 04:56:57

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

代码语言:javascript
运行
复制
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语句之外的队列中弹出。我认为如果在match中有整个.lock().unwrap().pop()语句,那么整个match块的内容都会被锁住。

但是,我不确定如果您对您使用的队列机箱执行相同的操作,它为什么不能工作。我也是一个Rust初学者,所以其中一些对我来说也是不清楚的。

我对您的代码所做的更改可以在这里看到:https://pastebin.com/ZrXrsgzf。我测试了它,它运行了(至少它通过了它最初被卡住的地方)。

我最近还在Rust中实现了一个网络爬虫,并在here上写了关于它的文章。

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

https://stackoverflow.com/questions/60103516

复制
相关文章

相似问题

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