# How to print the busying scheduler size of ExecutionContext::Parallel?

**URL:** <https://forum.crystal-lang.org/t/how-to-print-the-busying-scheduler-size-of-executioncontext-parallel/8761>\
**Category:** Help & Support\
**Created:** [March 6, 2026, 11:35am UTC](https://forum.crystal-lang.org/t/how-to-print-the-busying-scheduler-size-of-executioncontext-parallel/8761 "2026-03-06T11:35:52Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)\
**Post date:** [March 6, 2026, 11:35am UTC](https://forum.crystal-lang.org/t/how-to-print-the-busying-scheduler-size-of-executioncontext-parallel/8761/1 "2026-03-06T11:35:52Z")

</div>

the ExecutionContext::Parallel#size method is the number of threads that have been **started** , if it was increased, never see it reduce, not what I want, there was no #active? method to check current scheduler is still active too.

Thanks

---

<div class="post-metadata">

**Author:** ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)\
**Post date:** [March 13, 2026, 5:26am UTC](https://forum.crystal-lang.org/t/how-to-print-the-busying-scheduler-size-of-executioncontext-parallel/8761/2 "2026-03-13T05:26:20Z")

</div>

referenced PR:

> <https://github.com/crystal-lang/crystal/pull/16719>
>
> I started implementing "slow parallelism" to replace the "eager parallelism" tha…t was currently implemented.
> 
> \_Eager parallelism\_ tries to actively wake a scheduler on every fiber enqueue be it local to the context or from an external context.
> 
> \_Slow parallelism\_ tries to wake a scheduler on external context enqueues only (no scheduler might be active) and relies on the monitor thread to check if parallelism needs to be increased at "slow" intervals (every 100ms), at most doubling active schedulers (from 1 to 2 after 0.1s, ..., 32 after 0.5s, ...) to "slowly" reach capacity.
> 
> This should improve efficiency (not necessarily immediate performance): faster local enqueues, fibers can complete before we even need parallelism to kick-in (no need to increase), and it avoids edge case situations where a CPU busy fiber to hog the scheduler (fiber enqueues are no longer required for parallelism to increase).
> 
> As an example, this is the CPU graph of the "not well" example from #16707 on my local CPU (28 cores):
> 
> \- first Crystal 1.19.1 with 16 cores (~15% CPU) :snail: 
> \- followed by this PR with 16 cores (~58% CPU) :eagle: 
> \- and finally this PR with all 28 cores (100% CPU) :rocket: 
> 
> \<img width="1883" height="583" alt="Image" src="https://github.com/user-attachments/assets/99d387eb-7f02-4a50-b621-1e59c6594d30" /\>
> 
> We can definitely see the parallelism "slowly" increasing to reach full capacity and keep at it. The "well" example behaves exactly the same.
> 
> Nice for a first run attempt 😅

> <https://github.com/crystal-lang/crystal/pull/16732>
>
> Consolidates the \`@spinning\`, \`@waiting\` and \`@parked\` booleans into a single \`@…state\` enum.
> 
> Adds the \`NONE\` state to know whether a scheduler has been started so we don't consider a never started scheduler as running.
> 
> This reduces the need for the \`@started\` counter on the parallel context, and refactors \`Parallel#size\` to return a more correct value, but still only informational (maybe slightly off on race conditions).
> 
> \_Following this PR we could drop the PARKED state and instead set the scheduler's state back to NONE and return the thread to the thread pool and we wouldn't need \`@started\` anymore.\_
> 
> Related to #16719.
