Skip to content

Commit 4422355

Browse files
jdantoniojerry-dantonio
authored andcommitted
Testing threads and forking.
1 parent bfbe92d commit 4422355

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#!/usr/bin/env ruby
2+
3+
$: << File.expand_path('../../lib', __FILE__)
4+
5+
require 'benchmark'
6+
require 'benchmark/ips'
7+
require 'concurrent'
8+
9+
IPS_JOB_COUNT = 250_000
10+
BM_JOB_COUNT = 100_000
11+
BM_TEST_COUNT = 3
12+
13+
OPTIONS = {
14+
max_threads: 1,
15+
max_queue: [BM_JOB_COUNT, IPS_JOB_COUNT].max + 2,
16+
fallback_policy: :abort
17+
}
18+
19+
class DollarDollarThreadPoolExecutor < Concurrent::ThreadPoolExecutor
20+
def ns_initialize(opts)
21+
super(opts)
22+
@ruby_pid = $$
23+
end
24+
25+
private
26+
27+
def ns_execute(*args, &task)
28+
ns_reset_if_forked
29+
super
30+
end
31+
32+
def ns_reset_if_forked
33+
if $$ != @ruby_pid
34+
@queue.clear
35+
@ready.clear
36+
@pool.clear
37+
@ruby_pid = $$
38+
end
39+
end
40+
end
41+
42+
executor = DollarDollarThreadPoolExecutor.new
43+
20.times.map { Concurrent::Future.execute(executor: executor) { 1 } }.each(&:wait!)
44+
print "Executor is idle\n"
45+
fork do
46+
print "Posting forked job...\n"
47+
Concurrent::Future.execute(executor: executor) { 7 }.wait!
48+
print "Done\n"
49+
end
50+
51+
sleep(2)
52+
print "\n"
53+
54+
EXECUTORS = [
55+
Concurrent::ThreadPoolExecutor,
56+
DollarDollarThreadPoolExecutor
57+
]
58+
59+
def warmup(executor_class)
60+
executor = executor_class.new(OPTIONS)
61+
latch = Concurrent::CountDownLatch.new
62+
executor.post{ latch.count_down }
63+
latch.wait
64+
65+
return executor
66+
end
67+
68+
def test(executor, job_count)
69+
latch = Concurrent::CountDownLatch.new
70+
job_count.times { executor.post{ nil } }
71+
executor.post{ latch.count_down }
72+
latch.wait
73+
end
74+
75+
Benchmark.bmbm do |bm|
76+
EXECUTORS.each do |executor_class|
77+
executor = warmup(executor_class)
78+
BM_TEST_COUNT.times do |i|
79+
bm.report("#{executor_class.to_s} ##{i + 1}") do
80+
test(executor, BM_JOB_COUNT)
81+
end
82+
end
83+
end
84+
end
85+
86+
print "\n\n"
87+
88+
Benchmark.ips do |bm|
89+
EXECUTORS.each do |executor_class|
90+
executor = warmup(executor_class)
91+
bm.report(executor_class.to_s) do
92+
test(executor, IPS_JOB_COUNT)
93+
end
94+
end
95+
96+
bm.compare!
97+
end
98+
99+
__END__
100+
MacBook Pro (Retina, 15-inch, Mid 2015)
101+
Processor 2.8 GHz Intel Core i7
102+
Memory 16 GB 1600 MHz DDR3
103+
104+
[09:29:24 jerry.dantonio ~/Projects/FOSS/concurrent-ruby (fork-in-the-road)]
105+
$ ./examples/benchmark_thread_pool_executor.rb
106+
Executor is idle
107+
Posting forked job...
108+
Done
109+
110+
Rehearsal ---------------------------------------------------------------------
111+
Concurrent::ThreadPoolExecutor #1 0.570000 0.290000 0.860000 ( 0.697221)
112+
Concurrent::ThreadPoolExecutor #2 0.600000 0.280000 0.880000 ( 0.721201)
113+
Concurrent::ThreadPoolExecutor #3 0.500000 0.170000 0.670000 ( 0.576821)
114+
DollarDollarThreadPoolExecutor #1 0.630000 0.340000 0.970000 ( 0.771321)
115+
DollarDollarThreadPoolExecutor #2 0.550000 0.240000 0.790000 ( 0.645324)
116+
DollarDollarThreadPoolExecutor #3 0.500000 0.170000 0.670000 ( 0.569596)
117+
------------------------------------------------------------ total: 4.840000sec
118+
119+
user system total real
120+
Concurrent::ThreadPoolExecutor #1 0.520000 0.320000 0.840000 ( 0.627584)
121+
Concurrent::ThreadPoolExecutor #2 0.480000 0.170000 0.650000 ( 0.540811)
122+
Concurrent::ThreadPoolExecutor #3 0.460000 0.120000 0.580000 ( 0.504568)
123+
DollarDollarThreadPoolExecutor #1 0.530000 0.250000 0.780000 ( 0.645633)
124+
DollarDollarThreadPoolExecutor #2 0.500000 0.220000 0.720000 ( 0.585540)
125+
DollarDollarThreadPoolExecutor #3 0.490000 0.170000 0.660000 ( 0.560775)
126+
127+
128+
Calculating -------------------------------------
129+
Concurrent::ThreadPoolExecutor
130+
1.000 i/100ms
131+
DollarDollarThreadPoolExecutor
132+
1.000 i/100ms
133+
-------------------------------------------------
134+
Concurrent::ThreadPoolExecutor
135+
0.631 (± 0.0%) i/s - 4.000 in 6.425371s
136+
DollarDollarThreadPoolExecutor
137+
0.644 (± 0.0%) i/s - 4.000 in 6.279399s
138+
139+
Comparison:
140+
DollarDollarThreadPoolExecutor: 0.6 i/s
141+
Concurrent::ThreadPoolExecutor: 0.6 i/s - 1.02x slower
142+

examples/test_threads_and_forks.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env ruby
2+
3+
main = Thread.main
4+
t = Thread.new { sleep(2); print "Inside: #{t.inspect}\n" }
5+
3.times { fork { print "Fork #{$$}: #{t.inspect}, #{main.inspect}, #{Thread.main.inspect}\n" } }
6+
t.join
7+
8+
print "\n"
9+
10+
class ThreadMainTester
11+
attr_reader :main
12+
def initialize
13+
@main = Thread.main
14+
end
15+
end
16+
17+
def log(tester = nil)
18+
parentlog = tester ? ", parent main #{tester.main.inspect}" : ""
19+
print "pid #{$$}, Thread.main #{Thread.main.inspect}#{parentlog}\n"
20+
end
21+
22+
TESTS = 3
23+
testers = TESTS.times.collect { ThreadMainTester.new }
24+
log
25+
testers.each do |tester|
26+
fork { log(tester) }
27+
end
28+
sleep(1)
29+
30+
__END__
31+
32+
[17:53:58 Jerry ~/Projects/ruby-concurrency/concurrent-ruby (fork-in-the-road)]
33+
$ ./examples/test_threads_and_forks.rb
34+
Fork 2116: #<Thread:0x007fe44c027e60@./examples/test_threads_and_forks.rb:4 dead>, #<Thread:0x007fe44a8c03f8 run>, #<Thread:0x007fe44a8c03f8 run>
35+
Fork 2117: #<Thread:0x007fe44c027e60@./examples/test_threads_and_forks.rb:4 dead>, #<Thread:0x007fe44a8c03f8 run>, #<Thread:0x007fe44a8c03f8 run>
36+
Fork 2118: #<Thread:0x007fe44c027e60@./examples/test_threads_and_forks.rb:4 dead>, #<Thread:0x007fe44a8c03f8 run>, #<Thread:0x007fe44a8c03f8 run>
37+
Inside: #<Thread:0x007fe44c027e60@./examples/test_threads_and_forks.rb:4 run>
38+
39+
pid 2115, Thread.main #<Thread:0x007fe44a8c03f8 run>
40+
pid 2120, Thread.main #<Thread:0x007fe44a8c03f8 run>, parent main #<Thread:0x007fe44a8c03f8 run>
41+
pid 2121, Thread.main #<Thread:0x007fe44a8c03f8 run>, parent main #<Thread:0x007fe44a8c03f8 run>
42+
pid 2122, Thread.main #<Thread:0x007fe44a8c03f8 run>, parent main #<Thread:0x007fe44a8c03f8 run>

0 commit comments

Comments
 (0)