我有一个结构:
struct MyData {
x: i32
}
我想在这个结构上异步启动一个长操作。
我的第一次尝试是:
fn foo(&self) { //should return immediately
std::thread::Thread::spawn(move || {
println!("{:?}",self.x); //consider a very long operation
});
}
显然编译器cannot infer an appropriate lifetime due to conflicting requirements
因为self
可能在堆栈帧上,因此在操作在不同堆栈帧上运行时无法保证存在。
为了解决这个问题,我尝试复制self
并将该副本提供给新主题:
fn foo(&self) { //should return immediately
let clone = self.clone();
std::thread::Thread::spawn(move || {
println!("{:?}",clone.x); //consider a very long operation
});
}
我认为这不会编译,因为现在clone
位于堆栈帧上,与之前类似。我也尝试在线程中执行clone
,但是也没有编译,我认为是出于类似的原因。
然后我决定也许可以使用channel
将复制的数据推送到线程中,理论上可能channel
可以在线程之间神奇地移动(复制?)堆栈分配的数据由this example in the documentation建议。但是,编译器无法推断出生命周期:
fn foo(&self) { //should return immediately
let (tx, rx) = std::sync::mpsc::channel();
tx.send(self.clone());
std::thread::Thread::spawn(move || {
println!("{:?}",rx.recv().unwrap().x); //consider a very long operation
});
}
最后,我决定明确地将我的结构复制到堆上,并将Arc传递给线程。但即使在这里,编译器也无法计算出生命周期:
fn foo(&self) { //should return immediately
let arc = std::sync::Arc::new(self.clone());
std::thread::Thread::spawn(move || {
println!("{:?}",arc.clone().x); //consider a very long operation
});
}
好借借检查员,我放弃了。如何将self
的副本放到我的新主题上?
答案 0 :(得分:4)
我认为您的问题仅仅是因为您的结构未导出Clone
特征。您可以通过在结构定义之前添加#[derive(Clone)]
来编译和运行第二个示例。
我在编译器行为中不明白的是它试图在这里使用的.clone()
函数。您的结构确实没有实现Clone
特征,因此默认情况下不应该有.clone()
函数。
您可能还需要在功能中考虑按值self
按值,并让您的来电者决定是应该进行克隆,还是只是移动。
答案 1 :(得分:2)
作为替代解决方案,您可以使用thread::scoped
并维护线程的句柄。这允许线程保存引用,而无需将其复制到:
#![feature(old_io,std_misc)]
use std::thread::{self,JoinGuard};
use std::old_io::timer;
use std::time::duration::Duration;
struct MyData {
x: i32,
}
// returns immediately
impl MyData {
fn foo(&self) -> JoinGuard<()> {
thread::scoped(move || {
timer::sleep(Duration::milliseconds(300));
println!("{:?}", self.x); //consider a very long operation
timer::sleep(Duration::milliseconds(300));
})
}
}
fn main() {
let d = MyData { x: 42 };
let _thread = d.foo();
println!("I'm so fast!");
}