Rak*_*tty 6 multithreading rust
我正在编写一个程序,该程序从网站列表中抓取数据并将其存储到名为 的结构中,Listing然后将其收集到名为 的最终结构中Listings。
use std::{ thread,\n sync::{ Arc, Mutex }\n };\n\nfn main() {\n // ... some declarations\n let sites_count = site_list.len(); // site_list is a vector containing the list of websites\n\n // The variable to be updated by the thread instances ( `Listing` is a struct holding the information ) \n let listings: Arc<Mutex<Vec<Vec<types::Listing<String>>>>> = Arc::new(Mutex::new(Vec::new()));\n\n // A vector containing all the JoinHandles for the spawned threads\n let mut fetch_handle: Vec<thread::JoinHandle<()>> = Vec::new();\n\n // Spawn a thread for each concurrent website\n for i in 0..sites_count { \n let slist = Arc::clone(&site_list);\n let listng = Arc::clone(&listings);\n fetch_handle.push(\n thread::spawn(move || {\n println!("\xe2\x8c\x9b Spawned Thread: {}",i);\n let site_profile = read_profile(&slist[i]);\n let results = function1(function(2)) // A long list of functions from a submodule that make the http request and parse the data into `Listing`\n listng.lock().unwrap().push(results);\n }));\n }\n \n for thread in fetch_handle.iter_mut() { \n thread.join().unwrap();\n }\n\n // This is the one line version of the above for loop - yields the same error.\n // fetch_handle.iter().map(|thread| thread.join().unwrap()); \n\n // The final println to just test feed the target struct `Listings` with the values\n println!("{}",types::Listings{ date_time: format!("{}", chrono::offset::Local::now()),\n category: category.to_string(),\n query: (&search_query).to_string(),\n listings: listings.lock().unwrap() // It prevents me from owning this variable\n }.to_json());\n}\n\nRun Code Online (Sandbox Code Playgroud)\n我偶然发现了这个错误
\nerror[E0507]: cannot move out of `*thread` which is behind a mutable reference\n --> src/main.rs:112:9\n |\n112 | thread.join().unwrap();\n | ^^^^^^ move occurs because `*thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait\nRun Code Online (Sandbox Code Playgroud)\n它阻止我在 thread.join() for 循环之后拥有该变量。
\n当我尝试分配检查输出类型时
\nlet all_listings = listings.lock().unwrap()\nRun Code Online (Sandbox Code Playgroud)\nall_listings报告一种 MutexGuard(在线程 for 循环中也是如此,但它允许我在其上调用向量方法)并且不允许我拥有数据。\n我更改了结构中的数据类型Listings以保存参考而不是拥有它。但看来我对结构执行的操作要求.to_json()我拥有它的值。\n结构listings内部的类型声明Listings是Vec<Vec<Listing<T>>。
.join().unwrap()然而,当我将 移动到块的末尾thread::spawn()或应用于 for 循环内的句柄(同时禁用 external .join())时,此代码工作得很好。但这使得所有线程在链中执行,这是不可取的,因为使用线程的主要目的是同时执行具有不同数据值的相同函数。
总的来说,我对 Rust 还很陌生(自从我使用它以来已经 3 周了),这是我第一次实现多线程。在此之前,我只用 java 和 python 编写过单线程程序,所以如果可能的话,对菜鸟友好一些。不过,如有任何帮助,我们将不胜感激:)。
\nKev*_*son 10
我知道需要发生什么。首先,对于这种事情,我同意做into_iter你想做的事,但在我看来,它掩盖了原因。原因是,当您借用它时,它并不拥有该值,而该值对于结构join()上的方法来说是必需的JoinHandle<()>。你会注意到它的签名 takeself和 not&mut self或类似的东西。所以它需要那里有真实的物体。
为此,您需要将对象从其Vec<thread::JoinHandle<()>>内部取出。如前所述,into_iter这样做是因为它“销毁”现有对象Vec并接管它,因此它完全拥有内容,并且迭代返回要连接的“实际”对象,而无需副本。但您也可以一次拥有一个内容,remove如下所示:
while fetch_handle.len() > 0 {
let cur_thread = fetch_handle.remove(0); // moves it into cur_thread
cur_thread.join().unwrap();
}
Run Code Online (Sandbox Code Playgroud)
这代替了for上面的循环。如果您想尝试的话,可以链接游乐场中的完整示例。
我希望这能更清楚地说明如何处理无法复制的东西,但方法需要完全拥有它们,以及将它们从集合中取出的问题。想象一下,如果您只需要结束其中一个线程,并且您知道要结束哪一个,但又不想结束所有线程,该怎么办? Vec<_>::remove会起作用,但into_iter不会。
感谢您提出了一个让我思考的问题,并促使我自己去查找答案(并尝试一下)。我还在学习 Rust,所以这很有帮助。
编辑:
另一种使用pop()and 的方法while let:
while let Some(cur_thread) = fetch_handle.pop() {
cur_thread.join().unwrap();
}
Run Code Online (Sandbox Code Playgroud)
这从末端穿过它(pop将其从末端拉出,而不是前面),但也不会通过将其从前面拉出来重新分配或移动矢量内容。