Rust - 在多个工作人员之间共享结构中的哈希集的最佳方式
Rust - best way to share a hashset in a structure between multiple workers
我是 Rust 的新手,我正在尝试将我制作的 Go 网络爬虫移植到 Rust。
在 Go 中,我创建了一个 hashmap,它被多个 worker 使用(和共享)(生成相同函数的 go 例程)。使用 Mutexes 很容易解决这个问题,但我无法掌握如何在 Rust 中做同样的事情。
爬虫结构是:
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();
}
代码不知何故 运行s 但它几乎立即卡住了,没有处理任何东西。
我确定我只需要习惯 Rust 方法,但有人可以建议实现多线程爬虫的最佳方法是什么吗?
非常感谢
问题不在于哈希集,而在于队列。如果你用标准库中的 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),
},
_ => {}
}
}
}
最大的变化是我从匹配语句之外的队列中弹出。我想如果你在匹配中有整个 .lock().unwrap().pop()
语句,那么匹配块的全部内容都会被锁定。
但是,如果您对您使用的 Queue crate 执行相同操作,我不确定为什么它不起作用。我也是 Rust 初学者,所以其中一些我也不清楚。
可以在此处查看我对您的代码所做的更改:https://pastebin.com/ZrXrsgzf。我测试了它并且它运行了(至少它超过了它最初卡住的地方)。
我最近还用 Rust 实现了一个网络爬虫并写了一篇文章 here。
我是 Rust 的新手,我正在尝试将我制作的 Go 网络爬虫移植到 Rust。 在 Go 中,我创建了一个 hashmap,它被多个 worker 使用(和共享)(生成相同函数的 go 例程)。使用 Mutexes 很容易解决这个问题,但我无法掌握如何在 Rust 中做同样的事情。
爬虫结构是:
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();
}
代码不知何故 运行s 但它几乎立即卡住了,没有处理任何东西。 我确定我只需要习惯 Rust 方法,但有人可以建议实现多线程爬虫的最佳方法是什么吗?
非常感谢
问题不在于哈希集,而在于队列。如果你用标准库中的 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),
},
_ => {}
}
}
}
最大的变化是我从匹配语句之外的队列中弹出。我想如果你在匹配中有整个 .lock().unwrap().pop()
语句,那么匹配块的全部内容都会被锁定。
但是,如果您对您使用的 Queue crate 执行相同操作,我不确定为什么它不起作用。我也是 Rust 初学者,所以其中一些我也不清楚。
可以在此处查看我对您的代码所做的更改:https://pastebin.com/ZrXrsgzf。我测试了它并且它运行了(至少它超过了它最初卡住的地方)。
我最近还用 Rust 实现了一个网络爬虫并写了一篇文章 here。