Skip to content

fix: scheduler performance and correctness improvements#24

Merged
deepjoy merged 3 commits into
mainfrom
perf-bugs
Mar 14, 2026
Merged

fix: scheduler performance and correctness improvements#24
deepjoy merged 3 commits into
mainfrom
perf-bugs

Conversation

@deepjoy
Copy link
Copy Markdown
Owner

@deepjoy deepjoy commented Mar 14, 2026

  • Replace tokio::Mutex with std::sync::Mutex in ActiveTaskMap — most operations do trivial HashMap work with no .await, so a sync mutex avoids unnecessary runtime interaction. Methods that need async I/O (preempt_below, pause_all) now use two-phase locking: collect under the sync lock, then release before awaiting.
  • Eliminate O(N²) progress fan-out — remove the per-task broadcast listener that caused O(N×M) wakeups across N tasks and M events. ProgressReporter now updates the ActiveTaskMap directly via a sync call.
  • Break Arc cycle in SpawnContext — replace the strong Scheduler reference with WeakScheduler to prevent keeping SchedulerInner alive during graceful shutdown.
  • Track JoinHandles in ActiveTask — shutdown can now join spawned futures instead of polling active.count() in a 50ms busy loop. Graceful shutdown joins each handle with a per-task timeout budget.
  • Atomize single-task submit() — wrap in BEGIN IMMEDIATE transaction to match submit_batch() and prevent non-atomic multi-statement races.
  • Wake scheduler after task completion and failure — add missing work_notify.notify_one() calls after Completed and Failed event emissions so the scheduler loop dispatches pending work immediately instead of waiting for the next poll interval.

deepjoy added 3 commits March 14, 2026 05:55
…ate O(N²) progress fan-out

Switch ActiveTaskMap from tokio::Mutex to std::sync::Mutex since most
operations do trivial HashMap work with no .await. Restructure
preempt_below and pause_all with two-phase locking (collect under sync
lock, then async I/O). Give ProgressReporter a direct ActiveTaskMap
handle to update progress inline, removing the per-task broadcast
listener that caused O(N×M) wakeups across N tasks and M events.
…d atomize submit()

- Replace strong `Scheduler` with `WeakScheduler` in `SpawnContext` to
  prevent keeping `SchedulerInner` alive during graceful shutdown
- Track `JoinHandle`s in `ActiveTask` so shutdown can join spawned
  futures instead of polling `active.count()` in a busy loop
- Wrap single-task `submit()` in `BEGIN IMMEDIATE` transaction to match
  `submit_batch()` and prevent non-atomic multi-statement races
Add missing work_notify.notify_one() calls after Completed and Failed
event emissions so the scheduler loop wakes immediately to dispatch
pending work instead of waiting for the next poll interval.
@deepjoy deepjoy enabled auto-merge (squash) March 14, 2026 13:07
@deepjoy deepjoy merged commit 292e8d1 into main Mar 14, 2026
1 check passed
@github-actions github-actions Bot mentioned this pull request Mar 14, 2026
deepjoy pushed a commit that referenced this pull request Mar 14, 2026
## 🤖 New release

* `taskmill`: 0.3.0 -> 0.3.1 (✓ API compatible changes)

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

## [0.3.1](v0.3.0...v0.3.1)
- 2026-03-14

### Fixed

- scheduler performance and correctness improvements
([#24](#24))
- *(taskmill)* atomic parent resolution and weak scheduler reference in
TaskContext ([#22](#22))

### Other

- *(taskmill)* split large modules into focused submodules and optimize
completion hot path ([#25](#25))
- *(taskmill)* add integration tests and criterion benchmarks
([#21](#21))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant