我有一些 url,然后我将其分成块并同时迭代它们,使用克隆将结果保存在 vec 中:
pub fn collect_parm_list(url_list: Vec<String>) -> Result<Vec<String>, Box<dyn std::error::Error>> {
let shared_id_list = Arc::new(Mutex::new(vec![]));
for chunk in url_list.chunks(20) {
let mut handles = vec![];
for url in chunk {
let id_list = Arc::clone(&shared_id_list);
let handle = thread::spawn(move || {
// total: optionSale -> result -> total
let mut id_list_v = id_list.lock().unwrap();
id_list_v.push(url.to_string())
});
handles.push(handle);
}
// Wait for all threads to complete
for handle in handles {
handle.join().unwrap();
}
}
let x = shared_id_list.lock().unwrap();
Ok(x.to_vec())
}
我在借用数据时遇到错误:
url_list
does not live long enough borrowed value does not live long enough
在:对于url_list中的块。chunks(20){
您的问题是
.chunks()
不返回拥有事物的迭代器,而是返回一个切片。在这种情况下,这意味着虽然您有一个Vec<String>
,但.chunks()
会为您提供 的迭代器&[String]
,这意味着url
是一个&String
。然后您尝试将其提供给传递给 的闭包thread::spawn
,但提供给该函数的闭包必须是 ,这'static
意味着它们不会从任何本地借用。这是错误的根源:您传递给 的闭包thread::spawn
间接借用了url_list
。(旁白:不可否认,编译器没有很好地引导你找到
thread::spawn
问题的根源——调用。argument requires that "url_list" is borrowed for "'static"
表示它知道问题出在参数上,thread::spawn
但我不知道为什么它没有明确地强调那个调用。在我看来,这似乎是编译器诊断中的一个错误。)请注意,即使您连接了所有线程句柄,这也是有问题的。借用检查器不知道这种情况发生,也不知道这意味着什么;它只知道给出的闭包
thread::spawn
必须是'static
,但不是。(即使它知道这一点,正在运行的线程collect_parm_list
在解开的结果时可能会崩溃.join()
,这会导致它掉线url_list
,然后仍在运行的线程会出现使用后释放错误!)一个简单的修复方法是
let url = url.to_owned();
在生成线程之前添加,这将创建一个独立的副本,url
然后闭包将捕获它。或者,如果您有某种方式通知借用检查器,
url_list
即使当前线程崩溃,线程也无法存活,那么这将是安全的。这正是作用域线程所实现的!使用作用域线程,您可以避免复制url
,但它也Arc
允许您从输出列表中消除层。(您仍然需要同步访问。)这还允许您在线程完成时Mutex
使用,因为您知道此时没有线程仍然具有访问权限,因此您可以在不等待锁的情况下使用它。.into_inner()
Mutex
这种方法的代码也变得更加简单: