我可以从人造丝中获得类似纤维的行为吗?

Can I get fiber-like behavior from Rayon?

提问人:Zannick 提问时间:6/18/2023 最后编辑:Zannick 更新时间:6/18/2023 访问量:74

问:

Rayon 的工作原理是创建一个工作线程池,为每个工作线程分配一个工作队列,并允许具有空队列的工作线程来窃取工作。但是,如果闭包阻塞(例如,工作涉及在互斥锁下编辑共享资源),则工作人员是否能够在另一个工作项上取得进展,就像协作多任务光纤一样?

上下文:我有一个自定义的全局优先级工作队列,我的 rayon 线程从中弹出并推送到,但我没有为实际的 cpu 绑定工作项获得很好的并行化,我想也许我应该切换到 fibers(库)或 tokio。我的另一个选择是让线程池中的人造丝线程比弹出任务的“工作线程”多,并让它们创建子任务。

色人造丝

评论

1赞 Chayim Friedman 6/18/2023
否,如果任务阻塞,则线程被阻塞,不会被使用。如果您的模式实际上是 I/O 绑定的,而不是 CPU 绑定的,则应使用 代替 .但是,如果它因访问某些共享资源而被阻止,则可能无法有效地并行化它,除非它很少需要访问共享资源。tokiorayon
0赞 Zannick 6/18/2023
我更需要绿色任务(光纤)而不是异步 I/O 功能。tokio
0赞 Chayim Friedman 6/18/2023
I/O 是他们擅长的。你需要它们做什么?
0赞 Zannick 6/25/2023
我想我正在寻找的是一个互斥锁实现,它可以协作地直接屈服于不等待互斥锁的线程,以使其更简单。最后,我实际所做的是减少阻塞的最高级别任务的数量,并将其中的工作更好地拆分为非阻塞任务。

答:

1赞 Kevin Reid 6/18/2023 #1

如果某个工作单元当前无法取得进展,则可以调用 rayon::yield_now() 以允许其他工作继续进行。因此,原则上,您可以:

let guard = loop {
    match mutex.try_lock() {
        Ok(guard) => break guard,
        Err(TryLockError::WouldBlock) => rayon::yield_now(),
        Err(TryLockError::Poisoned(e)) => panic!("{e}"),
    }
};

但是,这将浪费一些 CPU 时间——锁被其他线程持有的时间越长——因为它不可能只在锁可用时才能“唤醒”。因此,如果您真的必须这样做,请谨慎行事并衡量性能。

一般来说,Rayon 最擅长计算任务,除了其他 Rayon 任务外,不涉及任何阻塞,具有严格的树形依赖关系。

如果您的任务具有更复杂的依赖项,请考虑改用,也许可以与以计算为中心的异步执行器(如 switchyard)一起使用。async

评论

0赞 Filipe Rodrigues 6/18/2023
如果返回,我建议实际阻止锁定互斥锁(这意味着没有其他任务可用)。您还可以在锁上使用超时,以允许在此期间创建新锁时执行新锁。rayon::yield_nowSome(Yield::Idle)rayon
0赞 Chayim Friedman 6/19/2023
这有一个问题,即锁可能直到最后才被获取,然后任务将忙于等待锁。