julia
cc10fd67 - scheduler: Add a work-stealing scheduler backend

Commit
52 days ago
scheduler: Add a work-stealing scheduler backend Add Base.Scheduler.Workstealing, a work-stealing task scheduler following the design shared by the Go runtime and Tokio: * a bounded FIFO ring of task references per worker thread with a packed (steal, real) head, so batch steals are visible to other thieves and index wraparound cannot be confused with an empty queue; the owner pushes with no atomic RMW and pops with a single CAS (no seq-cst fence, unlike a Chase-Lev deque) * a per-thread LIFO slot holding the most recently enqueued task for latency (capped at 3 consecutive polls to avoid starving the ring, and stealable so a busy owner cannot strand it) * thieves steal half of a victim ring in one claim, sweeping victims from their own successor so concurrent thieves fan out, copying raw slots into their own buffer with a single tail publish * a per-threadpool injection queue for cross-pool/foreign enqueues and ring overflow, striped over independently locked segments so an off-pool producer and the pool workers do not serialize on one lock; consumers refill in batches proportional to queue length * a fairness tick serving the injection queue every 61 polls so tasks respawning each other cannot starve injected work * consumed slots and links are always cleared so queues never pin dead tasks The scheduler is selected via Base.Scheduler.ChosenScheduler; Partr remains available as the alternative backend. Idle-thief throttling is provided by the runtime spinner accounting added separately; on top of it, the queues further improve recursive fork-join (task-per-node fib 2x at -t8, 3.2x at -t128 oversubscribed) and channel ping-pong (1.9x at -t64) over Partr on a 64-core machine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Amended: the claim protocol must wake a pinned task's thread directly. A task blocked in fetch/take! hosts its thread's sleep logic, keeping its tid pinned while the thread parks; when a dequeuer's claim fails it re-parks the task in the injection queue, and the pool wake it issued was gated by its own spinner slot — the task then cycles through the injection queue indefinitely while its only eligible thread sleeps (observed as a livelocked spinner at ~10M iterations/s with the rest of the pool parked). tryclaim now delivers the task to the pinned thread's sticky workqueue and wakes that thread directly (the mailbox pattern, as enq_work does for sticky tasks), keeping it out of the shared queues entirely, mirroring cd463b86b9 (#62371); a regression test drives the hosted-consumer pattern under a watchdog.
Author
Committer
Parents
Loading