atomic-ruby 0.15.3 → 0.15.4
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 +6 -1
- data/README.md +51 -14
- data/lib/atomic-ruby/atomic_thread_pool.rb +6 -13
- 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: e7c0136cf37fe5133affc1f090fa517636f5bfda0f5f43564a4877eee15bae3f
|
|
4
|
+
data.tar.gz: 0ae3a3aadabcc2bb69621df62188800451289a46032fa57a49c1af9326bcc31e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1786faa43a25379cbe68c9de2372c6168a62ab225436c45bbf5049791c39191e3ed75955ab2f5f6385069ddeb86640aa11ba431ce9f2ab54335005a61bd42092
|
|
7
|
+
data.tar.gz: 704c7e7224c9eec351aa0174f597c10c992f4e1594921b8ca91e9ad2df43a6b3eb2c260b9b25ab2d47f8fb0934afa9739ed5312fb00d5d7519d9283c6bf68170
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
-
## [0.15.
|
|
3
|
+
## [0.15.4] - 2026-09-01
|
|
4
|
+
|
|
5
|
+
- Keep temporary `AtomicThreadPool` workers alive for five seconds
|
|
6
|
+
- Speed up `AtomicThreadPool` scaling for blocking work
|
|
7
|
+
|
|
8
|
+
## [0.15.3] - 2026-08-31
|
|
4
9
|
|
|
5
10
|
- Prevent enqueues from racing `AtomicThreadPool#shutdown`
|
|
6
11
|
- Remove interrupted waiters from `AtomicConditionVariable`
|
data/README.md
CHANGED
|
@@ -268,7 +268,7 @@ puts "Atomic Ruby Atomic Bank Account: #{results[2].real.round(6)} seconds"
|
|
|
268
268
|
|
|
269
269
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
270
270
|
concurrent-ruby version: 1.3.8
|
|
271
|
-
atomic-ruby version: 0.15.
|
|
271
|
+
atomic-ruby version: 0.15.4
|
|
272
272
|
|
|
273
273
|
Balances:
|
|
274
274
|
Synchronized Bank Account Balance: 975
|
|
@@ -359,7 +359,7 @@ end
|
|
|
359
359
|
|
|
360
360
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
361
361
|
concurrent-ruby version: 1.3.8
|
|
362
|
-
atomic-ruby version: 0.15.
|
|
362
|
+
atomic-ruby version: 0.15.4
|
|
363
363
|
|
|
364
364
|
Warming up --------------------------------------
|
|
365
365
|
Synchronized Boolean Toggle 165.000 i/100ms
|
|
@@ -442,7 +442,7 @@ end
|
|
|
442
442
|
> bundle exec rake clobber && bundle exec rake compile && bundle exec ruby examples/atomic_condition_variable_benchmark.rb
|
|
443
443
|
|
|
444
444
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
445
|
-
atomic-ruby version: 0.15.
|
|
445
|
+
atomic-ruby version: 0.15.4
|
|
446
446
|
|
|
447
447
|
Warming up --------------------------------------
|
|
448
448
|
Synchronized Condition Variable Wait/Signal 4.062k i/100ms
|
|
@@ -517,7 +517,7 @@ end
|
|
|
517
517
|
> bundle exec rake clobber && bundle exec rake compile && bundle exec ruby examples/atomic_queue_benchmark.rb
|
|
518
518
|
|
|
519
519
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
520
|
-
atomic-ruby version: 0.15.
|
|
520
|
+
atomic-ruby version: 0.15.4
|
|
521
521
|
|
|
522
522
|
Warming up --------------------------------------
|
|
523
523
|
Synchronized Queue Push/Pop 184.000 i/100ms
|
|
@@ -547,7 +547,7 @@ require "benchmark"
|
|
|
547
547
|
require "concurrent-ruby"
|
|
548
548
|
require_relative "../lib/atomic-ruby"
|
|
549
549
|
|
|
550
|
-
|
|
550
|
+
fixed_results = []
|
|
551
551
|
|
|
552
552
|
2.times do |idx|
|
|
553
553
|
result = Benchmark.measure do
|
|
@@ -569,7 +569,36 @@ results = []
|
|
|
569
569
|
pool.wait_for_termination if idx == 0
|
|
570
570
|
end
|
|
571
571
|
|
|
572
|
-
|
|
572
|
+
fixed_results << result
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
adaptive_results = []
|
|
576
|
+
|
|
577
|
+
2.times do |idx|
|
|
578
|
+
result = Benchmark.measure do
|
|
579
|
+
pool = case idx
|
|
580
|
+
when 0 then Concurrent.new_io_executor
|
|
581
|
+
when 1 then AtomicThreadPool.new(size: 1, max_size: Float::INFINITY)
|
|
582
|
+
end
|
|
583
|
+
latch = case idx
|
|
584
|
+
when 0 then Concurrent::CountDownLatch.new(100)
|
|
585
|
+
when 1 then AtomicCountDownLatch.new(100)
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
100.times do
|
|
589
|
+
pool << proc do
|
|
590
|
+
sleep(0.2)
|
|
591
|
+
latch.count_down
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
latch.wait
|
|
596
|
+
pool.shutdown
|
|
597
|
+
# concurrent-ruby's #shutdown does not wait for threads to terminate
|
|
598
|
+
pool.wait_for_termination if idx == 0
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
adaptive_results << result
|
|
573
602
|
end
|
|
574
603
|
|
|
575
604
|
puts "\n"
|
|
@@ -577,9 +606,13 @@ puts "ruby version: #{RUBY_DESCRIPTION}"
|
|
|
577
606
|
puts "concurrent-ruby version: #{Concurrent::VERSION}"
|
|
578
607
|
puts "atomic-ruby version: #{AtomicRuby::VERSION}"
|
|
579
608
|
puts "\n"
|
|
580
|
-
puts "
|
|
581
|
-
puts "Concurrent Ruby Thread Pool:
|
|
582
|
-
puts "Atomic Ruby
|
|
609
|
+
puts "Fixed Pool Results:"
|
|
610
|
+
puts "Concurrent Ruby Fixed Thread Pool: #{fixed_results[0].real.round(6)} seconds"
|
|
611
|
+
puts "Atomic Ruby Fixed Thread Pool: #{fixed_results[1].real.round(6)} seconds"
|
|
612
|
+
puts "\n"
|
|
613
|
+
puts "Adaptive Pool Results:"
|
|
614
|
+
puts "Concurrent Ruby IO Thread Pool: #{adaptive_results[0].real.round(6)} seconds"
|
|
615
|
+
puts "Atomic Ruby Adaptive Thread Pool: #{adaptive_results[1].real.round(6)} seconds"
|
|
583
616
|
```
|
|
584
617
|
|
|
585
618
|
```
|
|
@@ -587,11 +620,15 @@ puts "Atomic Ruby Atomic Thread Pool: #{results[1].real.round(6)} seconds"
|
|
|
587
620
|
|
|
588
621
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
589
622
|
concurrent-ruby version: 1.3.8
|
|
590
|
-
atomic-ruby version: 0.15.
|
|
623
|
+
atomic-ruby version: 0.15.4
|
|
591
624
|
|
|
592
|
-
|
|
593
|
-
Concurrent Ruby Thread Pool:
|
|
594
|
-
Atomic Ruby
|
|
625
|
+
Fixed Pool Results:
|
|
626
|
+
Concurrent Ruby Fixed Thread Pool: 5.069464 seconds
|
|
627
|
+
Atomic Ruby Fixed Thread Pool: 4.791382 seconds
|
|
628
|
+
|
|
629
|
+
Adaptive Pool Results:
|
|
630
|
+
Concurrent Ruby IO Thread Pool: 0.22309 seconds
|
|
631
|
+
Atomic Ruby Adaptive Thread Pool: 0.61561 seconds
|
|
595
632
|
```
|
|
596
633
|
|
|
597
634
|
</details>
|
|
@@ -645,7 +682,7 @@ puts "Atomic Ruby Atomic Count Down Latch: #{results[1].total.round(6)} CPU seco
|
|
|
645
682
|
|
|
646
683
|
ruby version: ruby 4.0.6 (2026-07-14 revision 03b6d3f889) +YJIT +PRISM [arm64-darwin23]
|
|
647
684
|
concurrent-ruby version: 1.3.8
|
|
648
|
-
atomic-ruby version: 0.15.
|
|
685
|
+
atomic-ruby version: 0.15.4
|
|
649
686
|
|
|
650
687
|
Benchmark Results:
|
|
651
688
|
Concurrent Ruby Count Down Latch: 0.000511 CPU seconds, 2.001465 elapsed seconds
|
|
@@ -51,11 +51,10 @@ 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
|
-
AUTOSCALE_IDLE_TIME = 1
|
|
54
|
+
AUTOSCALE_IDLE_TIME = 5
|
|
56
55
|
AUTOSCALE_INTERVAL = 0.01
|
|
57
56
|
AUTOSCALE_WINDOW = 0.05
|
|
58
|
-
private_constant :
|
|
57
|
+
private_constant :AUTOSCALE_IDLE_TIME, :AUTOSCALE_INTERVAL, :AUTOSCALE_WINDOW
|
|
59
58
|
|
|
60
59
|
class Error < StandardError; end
|
|
61
60
|
|
|
@@ -71,7 +70,7 @@ module AtomicRuby
|
|
|
71
70
|
# if work remains queued while its active workers spend most of their time
|
|
72
71
|
# blocked outside the GVL, but not when Ruby execution is using the
|
|
73
72
|
# available CPU.
|
|
74
|
-
# Temporary workers
|
|
73
|
+
# Temporary workers remain available between bursts before the pool returns
|
|
75
74
|
# to its baseline size. Omitting `max_size` creates a fixed-size pool.
|
|
76
75
|
#
|
|
77
76
|
# @param size [Integer] The baseline number of worker threads (must be positive)
|
|
@@ -379,7 +378,6 @@ module AtomicRuby
|
|
|
379
378
|
previous_snapshot = @thread_pool_monitor.snapshot
|
|
380
379
|
pressure_started_at = nil
|
|
381
380
|
idle_started_at = nil
|
|
382
|
-
growth_samples = 0
|
|
383
381
|
phase_samples = [0, 0, 0]
|
|
384
382
|
|
|
385
383
|
loop do
|
|
@@ -395,7 +393,6 @@ module AtomicRuby
|
|
|
395
393
|
pressure_started_at = nil
|
|
396
394
|
previous_snapshot = snapshot
|
|
397
395
|
idle_started_at ||= now
|
|
398
|
-
growth_samples = 0
|
|
399
396
|
phase_samples.fill(0)
|
|
400
397
|
|
|
401
398
|
if now - idle_started_at >= AUTOSCALE_IDLE_TIME
|
|
@@ -412,13 +409,9 @@ module AtomicRuby
|
|
|
412
409
|
phase_samples.fill(0)
|
|
413
410
|
elsif now - pressure_started_at >= AUTOSCALE_WINDOW
|
|
414
411
|
if should_grow?(previous_snapshot, snapshot, phase_samples, now - pressure_started_at)
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
growth_samples = 0
|
|
419
|
-
end
|
|
420
|
-
else
|
|
421
|
-
growth_samples = 0
|
|
412
|
+
worker_count = @threads.length
|
|
413
|
+
workers_to_add = [worker_count, @queue.size, @max_size - worker_count].min
|
|
414
|
+
workers_to_add.times { spawn_worker(temporary: true) }
|
|
422
415
|
end
|
|
423
416
|
previous_snapshot = snapshot
|
|
424
417
|
pressure_started_at = now
|
data/lib/atomic-ruby/version.rb
CHANGED