atomic-ruby 0.15.3 → 0.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/README.md +55 -16
- data/lib/atomic-ruby/atomic_thread_pool.rb +70 -41
- data/lib/atomic-ruby/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6022f081e7f3e4ce545c40989e5a644beea0697da5d840f645ae3764fbb80e4e
|
|
4
|
+
data.tar.gz: 94b4312e55cfbda05127bde7ac74efd98da8708cb9835e718e7c02641f1d241a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bbcef6942791f3611e55c7c9806bd5daa4b71dd4bae4bedd255c0d1598e16c0ba50a19ae92423768fca04a4baafd80f464877f60960a7e43be0fc08ed2ffb3a3
|
|
7
|
+
data.tar.gz: '0883a4a401963ad0db23713c6ae6917bec1c3bd1cd3bd8ecff069cc63c99b3000a914ee0c9345cd9f2495f88f0d6da6c35a51057b80a56877409ba19ce3c5e4f'
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
-
## [0.15.
|
|
3
|
+
## [0.15.5] - 2026-09-03
|
|
4
|
+
|
|
5
|
+
- Adapt `AtomicThreadPool` scaling to workload pressure
|
|
6
|
+
|
|
7
|
+
## [0.15.4] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
- Keep temporary `AtomicThreadPool` workers alive for five seconds
|
|
10
|
+
- Speed up `AtomicThreadPool` scaling for blocking work
|
|
11
|
+
|
|
12
|
+
## [0.15.3] - 2026-08-31
|
|
4
13
|
|
|
5
14
|
- Prevent enqueues from racing `AtomicThreadPool#shutdown`
|
|
6
15
|
- Remove interrupted waiters from `AtomicConditionVariable`
|
data/README.md
CHANGED
|
@@ -122,8 +122,10 @@ p results.sort #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
|
122
122
|
|
|
123
123
|
Pass `max_size` to let the pool temporarily add workers when queued work is
|
|
124
124
|
held up by blocking operations. The pool measures time spent blocked outside
|
|
125
|
-
the GVL and CPU time used
|
|
126
|
-
Ruby execution is the bottleneck.
|
|
125
|
+
the GVL and CPU time used while running Ruby, so it does not add more threads
|
|
126
|
+
when Ruby execution is the bottleneck. Temporary workers remain available
|
|
127
|
+
between blocking bursts, but retire when Ruby execution becomes the bottleneck
|
|
128
|
+
or they remain idle.
|
|
127
129
|
|
|
128
130
|
```ruby
|
|
129
131
|
pool = AtomicThreadPool.new(size: 4, max_size: 16)
|
|
@@ -268,7 +270,7 @@ puts "Atomic Ruby Atomic Bank Account: #{results[2].real.round(6)} seconds"
|
|
|
268
270
|
|
|
269
271
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
270
272
|
concurrent-ruby version: 1.3.8
|
|
271
|
-
atomic-ruby version: 0.15.
|
|
273
|
+
atomic-ruby version: 0.15.5
|
|
272
274
|
|
|
273
275
|
Balances:
|
|
274
276
|
Synchronized Bank Account Balance: 975
|
|
@@ -359,7 +361,7 @@ end
|
|
|
359
361
|
|
|
360
362
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
361
363
|
concurrent-ruby version: 1.3.8
|
|
362
|
-
atomic-ruby version: 0.15.
|
|
364
|
+
atomic-ruby version: 0.15.5
|
|
363
365
|
|
|
364
366
|
Warming up --------------------------------------
|
|
365
367
|
Synchronized Boolean Toggle 165.000 i/100ms
|
|
@@ -442,7 +444,7 @@ end
|
|
|
442
444
|
> bundle exec rake clobber && bundle exec rake compile && bundle exec ruby examples/atomic_condition_variable_benchmark.rb
|
|
443
445
|
|
|
444
446
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
445
|
-
atomic-ruby version: 0.15.
|
|
447
|
+
atomic-ruby version: 0.15.5
|
|
446
448
|
|
|
447
449
|
Warming up --------------------------------------
|
|
448
450
|
Synchronized Condition Variable Wait/Signal 4.062k i/100ms
|
|
@@ -517,7 +519,7 @@ end
|
|
|
517
519
|
> bundle exec rake clobber && bundle exec rake compile && bundle exec ruby examples/atomic_queue_benchmark.rb
|
|
518
520
|
|
|
519
521
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
520
|
-
atomic-ruby version: 0.15.
|
|
522
|
+
atomic-ruby version: 0.15.5
|
|
521
523
|
|
|
522
524
|
Warming up --------------------------------------
|
|
523
525
|
Synchronized Queue Push/Pop 184.000 i/100ms
|
|
@@ -547,7 +549,7 @@ require "benchmark"
|
|
|
547
549
|
require "concurrent-ruby"
|
|
548
550
|
require_relative "../lib/atomic-ruby"
|
|
549
551
|
|
|
550
|
-
|
|
552
|
+
fixed_results = []
|
|
551
553
|
|
|
552
554
|
2.times do |idx|
|
|
553
555
|
result = Benchmark.measure do
|
|
@@ -569,7 +571,36 @@ results = []
|
|
|
569
571
|
pool.wait_for_termination if idx == 0
|
|
570
572
|
end
|
|
571
573
|
|
|
572
|
-
|
|
574
|
+
fixed_results << result
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
adaptive_results = []
|
|
578
|
+
|
|
579
|
+
2.times do |idx|
|
|
580
|
+
result = Benchmark.measure do
|
|
581
|
+
pool = case idx
|
|
582
|
+
when 0 then Concurrent.new_io_executor
|
|
583
|
+
when 1 then AtomicThreadPool.new(size: 1, max_size: Float::INFINITY)
|
|
584
|
+
end
|
|
585
|
+
latch = case idx
|
|
586
|
+
when 0 then Concurrent::CountDownLatch.new(100)
|
|
587
|
+
when 1 then AtomicCountDownLatch.new(100)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
100.times do
|
|
591
|
+
pool << proc do
|
|
592
|
+
sleep(0.2)
|
|
593
|
+
latch.count_down
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
latch.wait
|
|
598
|
+
pool.shutdown
|
|
599
|
+
# concurrent-ruby's #shutdown does not wait for threads to terminate
|
|
600
|
+
pool.wait_for_termination if idx == 0
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
adaptive_results << result
|
|
573
604
|
end
|
|
574
605
|
|
|
575
606
|
puts "\n"
|
|
@@ -577,9 +608,13 @@ puts "ruby version: #{RUBY_DESCRIPTION}"
|
|
|
577
608
|
puts "concurrent-ruby version: #{Concurrent::VERSION}"
|
|
578
609
|
puts "atomic-ruby version: #{AtomicRuby::VERSION}"
|
|
579
610
|
puts "\n"
|
|
580
|
-
puts "
|
|
581
|
-
puts "Concurrent Ruby Thread Pool:
|
|
582
|
-
puts "Atomic Ruby
|
|
611
|
+
puts "Fixed Pool Results:"
|
|
612
|
+
puts "Concurrent Ruby Fixed Thread Pool: #{fixed_results[0].real.round(6)} seconds"
|
|
613
|
+
puts "Atomic Ruby Fixed Thread Pool: #{fixed_results[1].real.round(6)} seconds"
|
|
614
|
+
puts "\n"
|
|
615
|
+
puts "Adaptive Pool Results:"
|
|
616
|
+
puts "Concurrent Ruby IO Thread Pool: #{adaptive_results[0].real.round(6)} seconds"
|
|
617
|
+
puts "Atomic Ruby Adaptive Thread Pool: #{adaptive_results[1].real.round(6)} seconds"
|
|
583
618
|
```
|
|
584
619
|
|
|
585
620
|
```
|
|
@@ -587,11 +622,15 @@ puts "Atomic Ruby Atomic Thread Pool: #{results[1].real.round(6)} seconds"
|
|
|
587
622
|
|
|
588
623
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
589
624
|
concurrent-ruby version: 1.3.8
|
|
590
|
-
atomic-ruby version: 0.15.
|
|
625
|
+
atomic-ruby version: 0.15.5
|
|
591
626
|
|
|
592
|
-
|
|
593
|
-
Concurrent Ruby Thread Pool:
|
|
594
|
-
Atomic Ruby
|
|
627
|
+
Fixed Pool Results:
|
|
628
|
+
Concurrent Ruby Fixed Thread Pool: 5.05313 seconds
|
|
629
|
+
Atomic Ruby Fixed Thread Pool: 4.753026 seconds
|
|
630
|
+
|
|
631
|
+
Adaptive Pool Results:
|
|
632
|
+
Concurrent Ruby IO Thread Pool: 0.221072 seconds
|
|
633
|
+
Atomic Ruby Adaptive Thread Pool: 0.233328 seconds
|
|
595
634
|
```
|
|
596
635
|
|
|
597
636
|
</details>
|
|
@@ -645,7 +684,7 @@ puts "Atomic Ruby Atomic Count Down Latch: #{results[1].total.round(6)} CPU seco
|
|
|
645
684
|
|
|
646
685
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
647
686
|
concurrent-ruby version: 1.3.8
|
|
648
|
-
atomic-ruby version: 0.15.
|
|
687
|
+
atomic-ruby version: 0.15.5
|
|
649
688
|
|
|
650
689
|
Benchmark Results:
|
|
651
690
|
Concurrent Ruby Count Down Latch: 0.000511 CPU seconds, 2.001465 elapsed seconds
|
|
@@ -51,11 +51,11 @@ module AtomicRuby
|
|
|
51
51
|
# @note This class is NOT Ractor-safe as it contains mutable thread state
|
|
52
52
|
# that cannot be safely shared across ractors.
|
|
53
53
|
class AtomicThreadPool
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
private_constant :
|
|
54
|
+
AUTOSCALE_IDLE_TIME = 5
|
|
55
|
+
AUTOSCALE_INITIAL_WINDOW = 0.002
|
|
56
|
+
AUTOSCALE_MAX_WINDOW = 0.05
|
|
57
|
+
AUTOSCALE_SAMPLES_PER_WINDOW = 5
|
|
58
|
+
private_constant :AUTOSCALE_IDLE_TIME, :AUTOSCALE_INITIAL_WINDOW, :AUTOSCALE_MAX_WINDOW, :AUTOSCALE_SAMPLES_PER_WINDOW
|
|
59
59
|
|
|
60
60
|
class Error < StandardError; end
|
|
61
61
|
|
|
@@ -71,8 +71,9 @@ module AtomicRuby
|
|
|
71
71
|
# if work remains queued while its active workers spend most of their time
|
|
72
72
|
# blocked outside the GVL, but not when Ruby execution is using the
|
|
73
73
|
# available CPU.
|
|
74
|
-
# Temporary workers
|
|
75
|
-
#
|
|
74
|
+
# Temporary workers remain available between blocking bursts, but retire
|
|
75
|
+
# when Ruby execution becomes the bottleneck or they remain idle. Omitting
|
|
76
|
+
# `max_size` creates a fixed-size pool.
|
|
76
77
|
#
|
|
77
78
|
# @param size [Integer] The baseline number of worker threads (must be positive)
|
|
78
79
|
# @param max_size [Integer, Float, nil] Maximum number of worker threads,
|
|
@@ -123,7 +124,8 @@ module AtomicRuby
|
|
|
123
124
|
@next_thread_number = 0
|
|
124
125
|
if adaptive?
|
|
125
126
|
@autoscale_available = AtomicConditionVariable.new
|
|
126
|
-
@
|
|
127
|
+
@idle_trim_requested = AtomicBoolean.new(false)
|
|
128
|
+
@ruby_cpu_trim_requested = AtomicBoolean.new(false)
|
|
127
129
|
@thread_pool_monitor = ThreadPoolMonitor.new
|
|
128
130
|
@thread_pool_monitor.start
|
|
129
131
|
end
|
|
@@ -156,7 +158,7 @@ module AtomicRuby
|
|
|
156
158
|
# @rbs (Proc work) -> void
|
|
157
159
|
def <<(work)
|
|
158
160
|
Thread.handle_interrupt(Exception => :never) do
|
|
159
|
-
@
|
|
161
|
+
@idle_trim_requested&.make_false
|
|
160
162
|
raise EnqueuedWorkAfterShutdownError unless @queue.push(work)
|
|
161
163
|
|
|
162
164
|
@work_available.signal
|
|
@@ -310,7 +312,8 @@ module AtomicRuby
|
|
|
310
312
|
|
|
311
313
|
# Creates a worker thread.
|
|
312
314
|
#
|
|
313
|
-
# Temporary workers
|
|
315
|
+
# Temporary workers retire when Ruby execution becomes the bottleneck or
|
|
316
|
+
# they remain idle.
|
|
314
317
|
#
|
|
315
318
|
# @param temporary [true, false] whether the worker belongs above the baseline
|
|
316
319
|
# @return [Thread]
|
|
@@ -334,10 +337,13 @@ module AtomicRuby
|
|
|
334
337
|
should_exit = false
|
|
335
338
|
|
|
336
339
|
@work_available.wait do
|
|
337
|
-
|
|
338
|
-
unless
|
|
339
|
-
|
|
340
|
-
|
|
340
|
+
should_exit = temporary && @ruby_cpu_trim_requested.true?
|
|
341
|
+
unless should_exit
|
|
342
|
+
work = @queue.pop
|
|
343
|
+
unless work
|
|
344
|
+
should_exit = @shutdown.true? && @queue.empty?
|
|
345
|
+
should_exit ||= temporary && @idle_trim_requested.true? && @queue.empty?
|
|
346
|
+
end
|
|
341
347
|
end
|
|
342
348
|
work || should_exit
|
|
343
349
|
end
|
|
@@ -345,6 +351,10 @@ module AtomicRuby
|
|
|
345
351
|
break if should_exit
|
|
346
352
|
|
|
347
353
|
@active_thread_count.swap { |current_count| current_count + 1 }
|
|
354
|
+
if temporary
|
|
355
|
+
work_started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
356
|
+
running_cpu_time_at_start = @thread_pool_monitor.snapshot[6]
|
|
357
|
+
end
|
|
348
358
|
begin
|
|
349
359
|
@thread_pool_monitor&.start_work
|
|
350
360
|
work.call
|
|
@@ -358,6 +368,14 @@ module AtomicRuby
|
|
|
358
368
|
ensure
|
|
359
369
|
@thread_pool_monitor&.stop_work
|
|
360
370
|
@active_thread_count.swap { |current_count| current_count - 1 }
|
|
371
|
+
if temporary && !@queue.empty?
|
|
372
|
+
elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - work_started_at
|
|
373
|
+
running_cpu_time = @thread_pool_monitor.snapshot[6] - running_cpu_time_at_start
|
|
374
|
+
if running_cpu_time * 2 >= elapsed_time * 1_000_000_000
|
|
375
|
+
@ruby_cpu_trim_requested.make_true
|
|
376
|
+
@work_available.broadcast
|
|
377
|
+
end
|
|
378
|
+
end
|
|
361
379
|
end
|
|
362
380
|
end
|
|
363
381
|
ensure
|
|
@@ -370,7 +388,10 @@ module AtomicRuby
|
|
|
370
388
|
thread
|
|
371
389
|
end
|
|
372
390
|
|
|
373
|
-
#
|
|
391
|
+
# Scales temporary workers in response to workload pressure.
|
|
392
|
+
#
|
|
393
|
+
# Sampling starts aggressively so the pool can react to short bursts, then
|
|
394
|
+
# backs off when more workers would not improve throughput.
|
|
374
395
|
#
|
|
375
396
|
# @return [void]
|
|
376
397
|
#
|
|
@@ -379,10 +400,11 @@ module AtomicRuby
|
|
|
379
400
|
previous_snapshot = @thread_pool_monitor.snapshot
|
|
380
401
|
pressure_started_at = nil
|
|
381
402
|
idle_started_at = nil
|
|
382
|
-
growth_samples = 0
|
|
383
403
|
phase_samples = [0, 0, 0]
|
|
404
|
+
sampling_window = AUTOSCALE_INITIAL_WINDOW
|
|
384
405
|
|
|
385
406
|
loop do
|
|
407
|
+
@ruby_cpu_trim_requested.make_false if @alive_thread_count.value <= @size
|
|
386
408
|
@autoscale_available.wait do
|
|
387
409
|
@shutdown.true? || !@queue.empty? || @alive_thread_count.value > @size
|
|
388
410
|
end
|
|
@@ -395,30 +417,37 @@ module AtomicRuby
|
|
|
395
417
|
pressure_started_at = nil
|
|
396
418
|
previous_snapshot = snapshot
|
|
397
419
|
idle_started_at ||= now
|
|
398
|
-
growth_samples = 0
|
|
399
420
|
phase_samples.fill(0)
|
|
421
|
+
sampling_window = AUTOSCALE_INITIAL_WINDOW
|
|
400
422
|
|
|
401
423
|
if now - idle_started_at >= AUTOSCALE_IDLE_TIME
|
|
402
|
-
@
|
|
424
|
+
@idle_trim_requested.make_true
|
|
403
425
|
@work_available.broadcast
|
|
404
426
|
end
|
|
405
427
|
else
|
|
406
|
-
@
|
|
428
|
+
@idle_trim_requested.make_false
|
|
407
429
|
idle_started_at = nil
|
|
408
430
|
|
|
409
431
|
if pressure_started_at.nil?
|
|
410
432
|
previous_snapshot = snapshot
|
|
411
433
|
pressure_started_at = now
|
|
412
434
|
phase_samples.fill(0)
|
|
413
|
-
elsif now - pressure_started_at >=
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
435
|
+
elsif now - pressure_started_at >= sampling_window
|
|
436
|
+
case scaling_direction(previous_snapshot, snapshot, phase_samples, now - pressure_started_at)
|
|
437
|
+
when :up
|
|
438
|
+
@ruby_cpu_trim_requested.make_false
|
|
439
|
+
worker_count = @threads.length
|
|
440
|
+
workers_to_add = [worker_count, @queue.size, @max_size - worker_count].min
|
|
441
|
+
workers_to_add.times { spawn_worker(temporary: true) }
|
|
442
|
+
sampling_window = AUTOSCALE_INITIAL_WINDOW
|
|
443
|
+
when :down
|
|
444
|
+
unless @ruby_cpu_trim_requested.true?
|
|
445
|
+
@ruby_cpu_trim_requested.make_true
|
|
446
|
+
@work_available.broadcast
|
|
419
447
|
end
|
|
448
|
+
sampling_window = [sampling_window * 2, AUTOSCALE_MAX_WINDOW].min
|
|
420
449
|
else
|
|
421
|
-
|
|
450
|
+
sampling_window = [sampling_window * 2, AUTOSCALE_MAX_WINDOW].min
|
|
422
451
|
end
|
|
423
452
|
previous_snapshot = snapshot
|
|
424
453
|
pressure_started_at = now
|
|
@@ -428,30 +457,28 @@ module AtomicRuby
|
|
|
428
457
|
end
|
|
429
458
|
end
|
|
430
459
|
|
|
431
|
-
sleep
|
|
460
|
+
sleep((@queue.empty? ? AUTOSCALE_MAX_WINDOW : sampling_window) / AUTOSCALE_SAMPLES_PER_WINDOW)
|
|
432
461
|
end
|
|
433
462
|
end
|
|
434
463
|
|
|
435
|
-
# Returns
|
|
464
|
+
# Returns the direction in which the pool should scale.
|
|
436
465
|
#
|
|
437
466
|
# Requiring workers to spend a majority of their time blocked outside the
|
|
438
|
-
# GVL recognizes blocking operations. The pool
|
|
439
|
-
#
|
|
440
|
-
#
|
|
441
|
-
# GVL contention.
|
|
467
|
+
# GVL recognizes blocking operations. The pool grows while Ruby execution
|
|
468
|
+
# uses less than half of one CPU and shrinks when Ruby execution becomes
|
|
469
|
+
# the bottleneck, without mistaking OS scheduling delays for GVL contention.
|
|
442
470
|
#
|
|
443
471
|
# @param previous_snapshot [Array<Integer>] previous GVL state snapshot
|
|
444
472
|
# @param snapshot [Array<Integer>] current GVL state snapshot
|
|
445
473
|
# @param phase_samples [Array<Integer>] sampled current GVL states
|
|
446
474
|
# @param elapsed_time [Float] seconds covered by the snapshots
|
|
447
|
-
# @return [
|
|
475
|
+
# @return [:up, :down, nil]
|
|
448
476
|
#
|
|
449
|
-
# @rbs (Array[Integer] previous_snapshot, Array[Integer] snapshot, Array[Integer] phase_samples, Float elapsed_time) ->
|
|
450
|
-
def
|
|
477
|
+
# @rbs (Array[Integer] previous_snapshot, Array[Integer] snapshot, Array[Integer] phase_samples, Float elapsed_time) -> (:up | :down)?
|
|
478
|
+
def scaling_direction(previous_snapshot, snapshot, phase_samples, elapsed_time)
|
|
451
479
|
@threads.select!(&:alive?)
|
|
452
480
|
workers = @threads
|
|
453
|
-
return
|
|
454
|
-
return false if @active_thread_count.value < workers.length
|
|
481
|
+
return if @active_thread_count.value < workers.length
|
|
455
482
|
|
|
456
483
|
running_time = snapshot[3] - previous_snapshot[3]
|
|
457
484
|
waiting_time = snapshot[4] - previous_snapshot[4]
|
|
@@ -459,15 +486,17 @@ module AtomicRuby
|
|
|
459
486
|
running_cpu_time = snapshot[6] - previous_snapshot[6]
|
|
460
487
|
total_time = running_time + waiting_time + blocked_time
|
|
461
488
|
|
|
462
|
-
minimum_measured_time = (
|
|
489
|
+
minimum_measured_time = (elapsed_time * 1_000_000_000 * workers.length / 2).to_i
|
|
463
490
|
if total_time < minimum_measured_time
|
|
464
491
|
running_time, waiting_time, blocked_time = phase_samples
|
|
465
492
|
total_time = running_time + waiting_time + blocked_time
|
|
466
493
|
end
|
|
467
494
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
495
|
+
ruby_cpu_bound = running_cpu_time * 2 >= elapsed_time * 1_000_000_000
|
|
496
|
+
blocking = total_time.positive? && blocked_time * 2 > total_time && !ruby_cpu_bound
|
|
497
|
+
|
|
498
|
+
return :up if blocking && workers.length < @max_size
|
|
499
|
+
return :down if ruby_cpu_bound && workers.length > @size
|
|
471
500
|
end
|
|
472
501
|
end
|
|
473
502
|
end
|
data/lib/atomic-ruby/version.rb
CHANGED