【发布时间】:2018-01-19 04:22:41
【问题描述】:
我正在尝试编写一个函数parallelize,它将函数B 作为参数并返回一个函数C,其中C 返回一个正在运行B 的线程的句柄。我知道这可能很笨拙或荒谬;它主要是作为一个学习项目。更高级别的目标是在迭代器上实现并行映射函数,其中列表的每个元素将映射到不同的线程(或最终可能通过线程池)。我很快意识到我的想法太过分了。根据我的描述,parallelize 的类型应该是什么?
【问题讨论】:
我正在尝试编写一个函数parallelize,它将函数B 作为参数并返回一个函数C,其中C 返回一个正在运行B 的线程的句柄。我知道这可能很笨拙或荒谬;它主要是作为一个学习项目。更高级别的目标是在迭代器上实现并行映射函数,其中列表的每个元素将映射到不同的线程(或最终可能通过线程池)。我很快意识到我的想法太过分了。根据我的描述,parallelize 的类型应该是什么?
【问题讨论】:
让我们一步一步来:
一个函数
parallelize
fn parallelize() {
unimplemented!()
}
是的,这是一个功能。
论证一个函数 B
我假设你希望函数能够返回一些东西,所以我将使用泛型类型R。
fn parallelize<B, R>(function: B)
where
B: FnOnce() -> R,
{
unimplemented!()
}
返回一个函数 C
哦哦。你can't do this cleanly in Rust yet。这意味着我们将返回一个 boxed trait 对象
fn parallelize<B, R>(function: B) -> Box<FnOnce()>
where
B: FnOnce() -> R,
{
unimplemented!()
}
其中 C 返回一个正在运行 B 的线程的句柄
use std::thread::JoinHandle;
fn parallelize<B, R>(function: B) -> Box<FnOnce() -> JoinHandle<R>>
where
B: FnOnce() -> R,
{
unimplemented!()
}
还有你的签名。到这里就搞定了!
.....
当然,还有更多工作要做。例如,您没有说明线程应该何时真正开始。这意味着我可以选择,而且我选择最简单的方法——线程在调用者请求句柄时启动。
use std::thread::{self, JoinHandle};
fn parallelize<B, R>(function: B) -> Box<FnOnce() -> JoinHandle<R>>
where
B: Send + FnOnce() -> R + 'static,
R: Send + 'static,
{
Box::new(|| thread::spawn(function))
}
我想你也可以立即开始:
use std::thread::{self, JoinHandle};
fn parallelize<B, R>(function: B) -> Box<FnOnce() -> JoinHandle<R>>
where
B: Send + FnOnce() -> R + 'static,
R: Send + 'static,
{
let handle = thread::spawn(function);
Box::new(|| handle)
}
我不知道为什么你会做第二个;在这种情况下,您不妨直接返回句柄。如果您这样做,您不妨直接致电thread::spawn。
哦,我想我不能越过你的那些额外的特质界限,是吗?在调用thread::spawn 时,您必须确保在线程退出之前传递的任何内容都不会停止有效(因此'static)并且可以安全地在线程之间传输(因此Send)。
更高层次的目标是在迭代器上实现并行映射函数
存在并称为Rayon。
另见:
【讨论】: