Skip to content

Commit ea17731

Browse files
Add benchmark.
1 parent cdda64f commit ea17731

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed

benchmark/queue.rb

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
# Released under the MIT License.
5+
# Copyright, 2025, by Samuel Williams.
6+
7+
require "sus/fixtures/benchmark"
8+
require "async/queue"
9+
require "async"
10+
11+
describe "Async::Queue Performance" do
12+
include Sus::Fixtures::Benchmark
13+
14+
let(:queue) {Async::Queue.new}
15+
16+
with "single-threaded operations" do
17+
measure "enqueue and dequeue pairs" do |repeats|
18+
Async do
19+
repeats.times do
20+
queue.push("item")
21+
queue.dequeue
22+
end
23+
end
24+
end
25+
26+
measure "batch enqueue" do |repeats|
27+
repeats.times do
28+
Async do
29+
# Create a batch of 100 items each time
30+
items = Array.new(100) {|i| "item-#{i}"}
31+
queue.enqueue(*items)
32+
# Clear queue for next iteration
33+
100.times {queue.dequeue}
34+
end
35+
end
36+
end
37+
38+
measure "batch dequeue" do |repeats|
39+
repeats.times do
40+
Async do
41+
# Pre-populate queue with 100 items
42+
items = Array.new(100) {|i| "item-#{i}"}
43+
queue.enqueue(*items)
44+
45+
# Measure dequeue operations
46+
100.times do
47+
queue.dequeue
48+
end
49+
end
50+
end
51+
end
52+
end
53+
54+
with "producer-consumer patterns" do
55+
measure "single producer, single consumer" do |repeats|
56+
repeats.times do
57+
Async do |task|
58+
# Producer
59+
producer = task.async do
60+
100.times do |i|
61+
queue.push("item-#{i}")
62+
end
63+
queue.push(nil) # Signal completion
64+
end
65+
66+
# Consumer
67+
consumer = task.async do
68+
count = 0
69+
while item = queue.dequeue
70+
count += 1
71+
end
72+
count
73+
end
74+
75+
[producer, consumer].each(&:wait)
76+
end
77+
end
78+
end
79+
80+
measure "multiple producers, single consumer", minimum: 3 do |repeats|
81+
repeats.times do
82+
Async do |task|
83+
num_producers = 4
84+
items_per_producer = 25 # 100 total items
85+
86+
# Multiple producers
87+
producers = num_producers.times.map do |i|
88+
task.async do
89+
items_per_producer.times do |j|
90+
queue.push("producer-#{i}-item-#{j}")
91+
end
92+
end
93+
end
94+
95+
# Single consumer
96+
consumer = task.async do
97+
total_items = num_producers * items_per_producer
98+
total_items.times do
99+
queue.dequeue
100+
end
101+
end
102+
103+
producers.each(&:wait)
104+
consumer.wait
105+
end
106+
end
107+
end
108+
109+
measure "single producer, multiple consumers", minimum: 3 do |repeats|
110+
repeats.times do
111+
Async do |task|
112+
num_consumers = 4
113+
total_items = 100
114+
115+
# Single producer
116+
producer = task.async do
117+
total_items.times do |i|
118+
queue.push("item-#{i}")
119+
end
120+
# Signal completion to all consumers
121+
num_consumers.times {queue.push(nil)}
122+
end
123+
124+
# Multiple consumers
125+
consumers = num_consumers.times.map do
126+
task.async do
127+
count = 0
128+
while item = queue.dequeue
129+
count += 1
130+
end
131+
count
132+
end
133+
end
134+
135+
producer.wait
136+
consumers.each(&:wait)
137+
end
138+
end
139+
end
140+
end
141+
142+
with "queue size operations" do
143+
measure "size checks with concurrent modifications" do |repeats|
144+
repeats.times do
145+
Async do |task|
146+
# Pre-populate with some items
147+
100.times {|i| queue.push("item-#{i}")}
148+
149+
# Reader checking size
150+
size_checker = task.async do
151+
100.times do
152+
queue.size
153+
end
154+
end
155+
156+
# Writer modifying queue
157+
modifier = task.async do
158+
50.times do |i|
159+
queue.push("new-item-#{i}")
160+
queue.dequeue if i.even?
161+
end
162+
end
163+
164+
[size_checker, modifier].each(&:wait)
165+
166+
# Clean up
167+
queue.size.times {queue.dequeue}
168+
end
169+
end
170+
end
171+
end
172+
173+
with "memory efficiency" do
174+
measure "queue growth and shrinkage" do |repeats|
175+
repeats.times do
176+
Async do
177+
# Fill the queue
178+
100.times {|i| queue.push("item-#{i}")}
179+
180+
# Empty the queue
181+
100.times {queue.dequeue}
182+
183+
# Fill again to test reuse
184+
100.times {|i| queue.push("item-#{i}")}
185+
186+
# Empty again
187+
100.times {queue.dequeue}
188+
end
189+
end
190+
end
191+
end
192+
end

0 commit comments

Comments
 (0)