Rust in Everything
基于 rayon-core 1.13.0

对外 API

rayon-core 的公开函数不多,这一部分把它们逐个拆开。每个函数都是 03 任务与 Latch 里几种零件的组合:选一种 Job 装闭包,推进本地 deque、全局注入队列或每线程的广播队列,再选一种 latch 等它(或者不等)。

flowchart LR
  subgraph block["阻塞:等任务做完才返回"]
    join["join / join_context"]
    scope["scope / scope_fifo / in_place_scope"]
    bc["broadcast"]
    inst["ThreadPool::install"]
  end
  subgraph detach["不阻塞:交出去就返回"]
    sp["spawn / spawn_fifo"]
    sbc["spawn_broadcast"]
  end
  subgraph coop["协作"]
    y["yield_now / yield_local"]
  end
  block --> sj["StackJob 或 HeapJob + 计数 latch"]
  detach --> hj["HeapJob / ArcJob + terminate_count"]
  coop --> fw["find_work / take_local_job 执行一个任务"]
函数闭包约束任务类型进哪个队列等待panic 去哪章
join(a, b)a、b:FnOnce + SendB 是 StackJob本线程 dequeSpinLatch,边等边干活传回调用方;两边都 panic 时传 A 的join
scope(op)op: Send;任务 Send + 'scopeHeapJobinject_or_pushCountLatch传回调用方,只传一个scope
in_place_scope(op)op 可以不是 SendHeapJob同上同上;池外线程用 LockLatch同上scope
spawn(f)FnOnce + Send + 'staticHeapJobinject_or_push不等panic_handler,没有就 abortspawn
spawn_fifo(f)同上HeapJob 进 JobFifoworker 上走本线程 FIFO,否则注入不等同上spawn
broadcast(op)Fn + Sync每线程一个 StackJob每线程的广播队列CountLatch传回调用方,按线程号取第一个broadcast
spawn_broadcast(op)Fn + Send + Sync + 'static一个 ArcJob同上不等同 spawnbroadcast
yield_now() / yield_local()————被执行任务自己的处理方式yield

ThreadPool 上的同名方法,阻塞的那几个(join、scope、scope_fifo)都是 self.install(|| 全局函数(..)):先进这个池,再调全局函数;全局函数总是作用于「调用线程所在的池」,不在任何池里就用全局池。install 本身和三条进池路径见 in_worker:从哪进池。

五章:

  1. join 与 join_context:主线 1 的全部细节。先推 B 再跑 A;弹回来的正是 B 就内联执行,否则执行它,本地空了就 wait_until;A panic 时也要等 B 做完。实测:join 的固定开销(E1)、等待时偷来的任务和持锁的冲突(E7,含一个确定性复现)。
  2. scope 家族:ScopeBase 的三个字段;scope 与 in_place_scope 在哪个线程跑 op;spawn 为什么一律 inject_or_push;'scope 生命周期;panic 只保留第一个(E11)。
  3. spawn 与 spawn_fifo:terminate_count 让池在任务跑完前不终止;没有 panic_handler 就 abort(E11);和 tokio 的 spawn 对照;在 async 代码里调 rayon 的三种写法(E5)。
  4. broadcast:每线程一个 FIFO 广播队列,worker 先清自己的广播队列再去偷;一次睡眠竞态的修复(#992)。
  5. yield_now 与 yield_local:在 rayon 任务里等条件时,把线程让给 rayon 而不是让给 OS。

本部分的实验

实验目录都在 exp-rayon/ 下,机器是 M2 Max(8 性能核 + 4 能效核),macOS,rustc 1.99.1,--release。

#目录看什么章
E1join-granularity/fib(36) 扫串行阈值:join 的固定开销和加速比join
E7lock-reentry/持锁调 rayon:等待时偷来的任务在同一线程上再次加锁;确定性复现 + 概率性死锁join
E11panics/join / scope / broadcast 传播哪个 panic;spawn / spawn_broadcast 无 handler 时 abortjoin、scope、spawn、broadcast
E5tokio-rayon/async 任务里直接调 par_iter、spawn_blocking、rayon::spawn + oneshot 对 tokio 心跳的影响spawn
E15broadcast-busy/一个 worker 忙 200 ms 时 broadcast 要等多久;反向:忙的任务定期 yield_localbroadcast
E16yield-poll/1 线程池里一个任务自旋等另一个任务:spin_loop 卡死,yield_now / yield_local 一次解开yield

计时类数字(E1、E5、E15)在 1 分钟和 5 分钟负载都低于 3 时取得,各页写了具体负载;E7、E11、E16 是正确性实验,结论不依赖负载,E7 的死锁概率随负载有变化,页面列出了每组的负载。

💬 关联讨论

发起讨论
加载中...