复制结构以在另一个线程上使用
Copying a struct for use on another thread
我有一个结构:
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
});
}
好吧借checker,我放弃了。如何将 self
的副本添加到我的新线程?
我认为你的问题仅仅是因为你的结构没有派生出 Clone
特性。您可以通过在结构定义之前添加 #[derive(Clone)]
来编译和 运行 第二个示例。
我在这里的编译器行为中不明白的是它试图在这里使用的 .clone()
函数。您的结构确实没有实现 Clone
特性,因此默认情况下不应具有 .clone()
函数。
您可能还需要考虑在您的函数中采用 self
by value,并让您的调用者决定是否应该进行克隆,或者只是移动。
作为替代解决方案,您可以使用 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!");
}
我有一个结构:
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
});
}
好吧借checker,我放弃了。如何将 self
的副本添加到我的新线程?
我认为你的问题仅仅是因为你的结构没有派生出 Clone
特性。您可以通过在结构定义之前添加 #[derive(Clone)]
来编译和 运行 第二个示例。
我在这里的编译器行为中不明白的是它试图在这里使用的 .clone()
函数。您的结构确实没有实现 Clone
特性,因此默认情况下不应具有 .clone()
函数。
您可能还需要考虑在您的函数中采用 self
by value,并让您的调用者决定是否应该进行克隆,或者只是移动。
作为替代解决方案,您可以使用 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!");
}