polyphony 0.36 → 0.42
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/.github/workflows/test.yml +11 -2
- data/.gitignore +2 -2
- data/.rubocop.yml +30 -0
- data/CHANGELOG.md +28 -2
- data/Gemfile +0 -11
- data/Gemfile.lock +15 -14
- data/README.md +2 -1
- data/Rakefile +7 -3
- data/TODO.md +28 -95
- data/docs/_config.yml +56 -7
- data/docs/_sass/custom/custom.scss +0 -30
- data/docs/_sass/overrides.scss +0 -46
- data/docs/{user-guide → _user-guide}/all-about-timers.md +0 -0
- data/docs/_user-guide/index.md +9 -0
- data/docs/{user-guide → _user-guide}/web-server.md +0 -0
- data/docs/api-reference/fiber.md +2 -2
- data/docs/api-reference/index.md +9 -0
- data/docs/api-reference/polyphony-process.md +1 -1
- data/docs/api-reference/thread.md +1 -1
- data/docs/faq.md +21 -11
- data/docs/getting-started/index.md +10 -0
- data/docs/getting-started/installing.md +2 -6
- data/docs/getting-started/overview.md +507 -0
- data/docs/getting-started/tutorial.md +27 -19
- data/docs/index.md +3 -2
- data/docs/main-concepts/concurrency.md +0 -5
- data/docs/main-concepts/design-principles.md +69 -21
- data/docs/main-concepts/extending.md +1 -1
- data/docs/main-concepts/index.md +9 -0
- data/examples/core/01-spinning-up-fibers.rb +1 -0
- data/examples/core/03-interrupting.rb +4 -1
- data/examples/core/04-handling-signals.rb +19 -0
- data/examples/core/xx-agent.rb +102 -0
- data/examples/core/xx-fork-cleanup.rb +22 -0
- data/examples/core/xx-sleeping.rb +14 -6
- data/examples/io/tunnel.rb +48 -0
- data/examples/io/xx-irb.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +13 -36
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
- data/examples/performance/xx-array.rb +11 -0
- data/examples/performance/xx-fiber-switch.rb +9 -0
- data/examples/performance/xx-snooze.rb +15 -0
- data/ext/{gyro → polyphony}/extconf.rb +2 -2
- data/ext/{gyro → polyphony}/fiber.c +18 -22
- data/ext/{gyro → polyphony}/libev.c +0 -0
- data/ext/{gyro → polyphony}/libev.h +0 -0
- data/ext/polyphony/libev_agent.c +718 -0
- data/ext/polyphony/libev_queue.c +216 -0
- data/ext/{gyro/gyro.c → polyphony/polyphony.c} +16 -46
- data/ext/{gyro/gyro.h → polyphony/polyphony.h} +25 -39
- data/ext/polyphony/polyphony_ext.c +23 -0
- data/ext/{gyro → polyphony}/socket.c +21 -18
- data/ext/polyphony/thread.c +206 -0
- data/ext/{gyro → polyphony}/tracing.c +1 -1
- data/lib/polyphony.rb +40 -44
- data/lib/polyphony/adapters/fs.rb +1 -4
- data/lib/polyphony/adapters/irb.rb +1 -1
- data/lib/polyphony/adapters/postgres.rb +6 -5
- data/lib/polyphony/adapters/process.rb +27 -23
- data/lib/polyphony/adapters/trace.rb +110 -105
- data/lib/polyphony/core/channel.rb +35 -35
- data/lib/polyphony/core/exceptions.rb +29 -29
- data/lib/polyphony/core/global_api.rb +94 -91
- data/lib/polyphony/core/resource_pool.rb +83 -83
- data/lib/polyphony/core/sync.rb +16 -16
- data/lib/polyphony/core/thread_pool.rb +49 -37
- data/lib/polyphony/core/throttler.rb +30 -23
- data/lib/polyphony/event.rb +27 -0
- data/lib/polyphony/extensions/core.rb +25 -17
- data/lib/polyphony/extensions/fiber.rb +269 -267
- data/lib/polyphony/extensions/io.rb +56 -26
- data/lib/polyphony/extensions/openssl.rb +5 -9
- data/lib/polyphony/extensions/socket.rb +29 -10
- data/lib/polyphony/extensions/thread.rb +19 -12
- data/lib/polyphony/net.rb +64 -60
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +4 -7
- data/test/helper.rb +14 -1
- data/test/stress.rb +17 -12
- data/test/test_agent.rb +124 -0
- data/test/{test_async.rb → test_event.rb} +15 -7
- data/test/test_ext.rb +25 -4
- data/test/test_fiber.rb +19 -10
- data/test/test_global_api.rb +4 -4
- data/test/test_io.rb +46 -24
- data/test/test_queue.rb +74 -0
- data/test/test_signal.rb +3 -40
- data/test/test_socket.rb +33 -0
- data/test/test_thread.rb +38 -16
- data/test/test_thread_pool.rb +2 -2
- data/test/test_throttler.rb +0 -1
- data/test/test_trace.rb +6 -5
- metadata +41 -57
- data/docs/_includes/nav.html +0 -51
- data/docs/_includes/prevnext.html +0 -17
- data/docs/_layouts/default.html +0 -106
- data/docs/api-reference.md +0 -11
- data/docs/api-reference/gyro-async.md +0 -57
- data/docs/api-reference/gyro-child.md +0 -29
- data/docs/api-reference/gyro-queue.md +0 -44
- data/docs/api-reference/gyro-timer.md +0 -51
- data/docs/api-reference/gyro.md +0 -25
- data/docs/getting-started.md +0 -10
- data/docs/main-concepts.md +0 -10
- data/docs/user-guide.md +0 -10
- data/examples/core/forever_sleep.rb +0 -19
- data/ext/gyro/async.c +0 -148
- data/ext/gyro/child.c +0 -127
- data/ext/gyro/gyro_ext.c +0 -33
- data/ext/gyro/io.c +0 -474
- data/ext/gyro/queue.c +0 -142
- data/ext/gyro/selector.c +0 -205
- data/ext/gyro/signal.c +0 -118
- data/ext/gyro/thread.c +0 -298
- data/ext/gyro/timer.c +0 -134
- data/test/test_timer.rb +0 -56
data/test/test_global_api.rb
CHANGED
@@ -202,9 +202,9 @@ class SpinLoopTest < MiniTest::Test
|
|
202
202
|
buffer = []
|
203
203
|
counter = 0
|
204
204
|
f = spin_loop(rate: 50) { buffer << (counter += 1) }
|
205
|
-
sleep 0.
|
205
|
+
sleep 0.2
|
206
206
|
f.stop
|
207
|
-
assert counter >=
|
207
|
+
assert counter >= 9 && counter <= 11
|
208
208
|
end
|
209
209
|
end
|
210
210
|
|
@@ -215,9 +215,9 @@ class ThrottledLoopTest < MiniTest::Test
|
|
215
215
|
f = spin do
|
216
216
|
throttled_loop(50) { buffer << (counter += 1) }
|
217
217
|
end
|
218
|
-
sleep 0.
|
218
|
+
sleep 0.2
|
219
219
|
f.stop
|
220
|
-
assert counter >=
|
220
|
+
assert counter >= 9 && counter <= 11
|
221
221
|
end
|
222
222
|
|
223
223
|
def test_throttled_loop_with_count
|
data/test/test_io.rb
CHANGED
@@ -2,30 +2,6 @@
|
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
4
|
|
5
|
-
class GyroIOTest < MiniTest::Test
|
6
|
-
def test_that_reading_works
|
7
|
-
i, o = IO.pipe
|
8
|
-
data = +''
|
9
|
-
sequence = []
|
10
|
-
watcher = Gyro::IO.new(i, :r)
|
11
|
-
spin {
|
12
|
-
sequence << 1
|
13
|
-
watcher.await
|
14
|
-
sequence << 2
|
15
|
-
i.read_nonblock(8192, data)
|
16
|
-
}
|
17
|
-
snooze
|
18
|
-
sequence << 3
|
19
|
-
spin do
|
20
|
-
o << 'hello'
|
21
|
-
sequence << 4
|
22
|
-
end
|
23
|
-
suspend
|
24
|
-
assert_equal 'hello', data
|
25
|
-
assert_equal [1, 3, 4, 2], sequence
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
5
|
class IOTest < MiniTest::Test
|
30
6
|
def setup
|
31
7
|
super
|
@@ -61,6 +37,52 @@ class IOTest < MiniTest::Test
|
|
61
37
|
@o.close
|
62
38
|
assert_equal 'foobarbaz', @i.read
|
63
39
|
end
|
40
|
+
|
41
|
+
def test_wait_io
|
42
|
+
results = []
|
43
|
+
i, o = IO.pipe
|
44
|
+
f = spin do
|
45
|
+
loop do
|
46
|
+
result = i.orig_read_nonblock(8192, exception: false)
|
47
|
+
results << result
|
48
|
+
case result
|
49
|
+
when :wait_readable
|
50
|
+
Thread.current.agent.wait_io(i, false)
|
51
|
+
else
|
52
|
+
break result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
snooze
|
58
|
+
o.write('foo')
|
59
|
+
o.close
|
60
|
+
|
61
|
+
result = f.await
|
62
|
+
|
63
|
+
assert_equal 'foo', f.await
|
64
|
+
assert_equal [:wait_readable, 'foo'], results
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_readpartial
|
68
|
+
i, o = IO.pipe
|
69
|
+
|
70
|
+
o << 'hi'
|
71
|
+
assert_equal 'hi', i.readpartial(3)
|
72
|
+
|
73
|
+
o << 'hi'
|
74
|
+
assert_equal 'h', i.readpartial(1)
|
75
|
+
assert_equal 'i', i.readpartial(1)
|
76
|
+
|
77
|
+
spin {
|
78
|
+
sleep 0.01
|
79
|
+
o << 'hi'
|
80
|
+
}
|
81
|
+
assert_equal 'hi', i.readpartial(2)
|
82
|
+
o.close
|
83
|
+
|
84
|
+
assert_raises(EOFError) { i.readpartial(1) }
|
85
|
+
end
|
64
86
|
end
|
65
87
|
|
66
88
|
class IOClassMethodsTest < MiniTest::Test
|
data/test/test_queue.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
class QueueTest < MiniTest::Test
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
@queue = Polyphony::Queue.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_pop
|
12
|
+
spin {
|
13
|
+
@queue << 42
|
14
|
+
}
|
15
|
+
v = @queue.shift
|
16
|
+
assert_equal 42, v
|
17
|
+
|
18
|
+
(1..4).each { |i| @queue << i }
|
19
|
+
buf = []
|
20
|
+
4.times { buf << @queue.shift }
|
21
|
+
assert_equal [1, 2, 3, 4], buf
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_multiple_waiters
|
25
|
+
a = spin { @queue.shift }
|
26
|
+
b = spin { @queue.shift }
|
27
|
+
|
28
|
+
@queue << :foo
|
29
|
+
@queue << :bar
|
30
|
+
|
31
|
+
assert_equal [:foo, :bar], Fiber.await(a, b)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_multi_thread_usage
|
35
|
+
t = Thread.new { @queue.push :foo }
|
36
|
+
assert_equal :foo, @queue.shift
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_shift_each
|
40
|
+
(1..4).each { |i| @queue << i }
|
41
|
+
buf = []
|
42
|
+
@queue.shift_each { |i| buf << i }
|
43
|
+
assert_equal [1, 2, 3, 4], buf
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_empty?
|
47
|
+
assert @queue.empty?
|
48
|
+
|
49
|
+
@queue << :foo
|
50
|
+
assert !@queue.empty?
|
51
|
+
|
52
|
+
assert_equal :foo, @queue.shift
|
53
|
+
assert @queue.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_fiber_removal_from_queue
|
57
|
+
f1 = spin { @queue.shift }
|
58
|
+
f2 = spin { @queue.shift }
|
59
|
+
f3 = spin { @queue.shift }
|
60
|
+
|
61
|
+
# let fibers run
|
62
|
+
snooze
|
63
|
+
|
64
|
+
f2.stop
|
65
|
+
snooze
|
66
|
+
|
67
|
+
@queue << :foo
|
68
|
+
@queue << :bar
|
69
|
+
|
70
|
+
assert_equal :foo, f1.await
|
71
|
+
assert_nil f2.await
|
72
|
+
assert_equal :bar, f3.await
|
73
|
+
end
|
74
|
+
end
|
data/test/test_signal.rb
CHANGED
@@ -2,41 +2,6 @@
|
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
4
|
|
5
|
-
class SignalTest < MiniTest::Test
|
6
|
-
def test_Gyro_Signal_constructor
|
7
|
-
sig = Signal.list['USR1']
|
8
|
-
count = 0
|
9
|
-
w = Gyro::Signal.new(sig)
|
10
|
-
|
11
|
-
spin {
|
12
|
-
loop {
|
13
|
-
w.await
|
14
|
-
count += 1
|
15
|
-
break
|
16
|
-
}
|
17
|
-
}
|
18
|
-
Thread.new do
|
19
|
-
orig_sleep 0.001
|
20
|
-
Process.kill(:USR1, Process.pid)
|
21
|
-
end
|
22
|
-
suspend
|
23
|
-
assert_equal 1, count
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_wait_for_signal_api
|
27
|
-
count = 0
|
28
|
-
spin do
|
29
|
-
Polyphony.wait_for_signal 'SIGHUP'
|
30
|
-
count += 1
|
31
|
-
end
|
32
|
-
|
33
|
-
snooze
|
34
|
-
Process.kill(:HUP, Process.pid)
|
35
|
-
snooze
|
36
|
-
assert_equal 1, count
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
5
|
class SignalTrapTest < Minitest::Test
|
41
6
|
def test_signal_exception_handling
|
42
7
|
i, o = IO.pipe
|
@@ -57,9 +22,8 @@ class SignalTrapTest < Minitest::Test
|
|
57
22
|
end
|
58
23
|
sleep 0.01
|
59
24
|
o.close
|
60
|
-
watcher = Gyro::Child.new(pid)
|
61
25
|
Process.kill('INT', pid)
|
62
|
-
|
26
|
+
Thread.current.agent.waitpid(pid)
|
63
27
|
buffer = i.read
|
64
28
|
assert_equal "3-interrupt\n", buffer
|
65
29
|
end
|
@@ -86,9 +50,8 @@ class SignalTrapTest < Minitest::Test
|
|
86
50
|
end
|
87
51
|
sleep 0.02
|
88
52
|
o.close
|
89
|
-
watcher = Gyro::Child.new(pid)
|
90
53
|
Process.kill('INT', pid)
|
91
|
-
|
54
|
+
Thread.current.agent.waitpid(pid)
|
92
55
|
buffer = i.read
|
93
56
|
assert_equal "3 - interrupted\n2 - terminated\n1 - terminated\n", buffer
|
94
57
|
end
|
@@ -130,7 +93,7 @@ class SignalTrapTest < Minitest::Test
|
|
130
93
|
o.close
|
131
94
|
sleep 0.1
|
132
95
|
Process.kill('INT', pid)
|
133
|
-
|
96
|
+
Thread.current.agent.waitpid(pid)
|
134
97
|
buffer = i.read
|
135
98
|
assert_equal "3-interrupt\n", buffer
|
136
99
|
end
|
data/test/test_socket.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
class SocketTest < MiniTest::Test
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_tcp
|
11
|
+
server = TCPServer.new('127.0.0.1', 1234)
|
12
|
+
|
13
|
+
server_fiber = spin do
|
14
|
+
while (socket = server.accept)
|
15
|
+
spin do
|
16
|
+
while (data = socket.gets(8192))
|
17
|
+
socket << data
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
snooze
|
24
|
+
client = TCPSocket.new('127.0.0.1', 1234)
|
25
|
+
client.write("1234\n")
|
26
|
+
assert_equal "1234\n", client.readpartial(8192)
|
27
|
+
client.close
|
28
|
+
ensure
|
29
|
+
server_fiber.stop
|
30
|
+
snooze
|
31
|
+
server&.close
|
32
|
+
end
|
33
|
+
end
|
data/test/test_thread.rb
CHANGED
@@ -1,20 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
|
+
require 'polyphony/adapters/trace'
|
4
5
|
|
5
6
|
class ThreadTest < MiniTest::Test
|
6
7
|
def test_thread_spin
|
7
8
|
buffer = []
|
8
9
|
f = spin { (1..3).each { |i| snooze; buffer << i } }
|
9
10
|
t = Thread.new do
|
11
|
+
sleep 0.01
|
10
12
|
s1 = spin { (11..13).each { |i| snooze; buffer << i } }
|
11
13
|
s2 = spin { (21..23).each { |i| snooze; buffer << i } }
|
14
|
+
sleep 0.02
|
12
15
|
Fiber.current.await_all_children
|
13
16
|
end
|
14
17
|
f.join
|
15
18
|
t.join
|
19
|
+
t = nil
|
16
20
|
|
17
21
|
assert_equal [1, 2, 3, 11, 12, 13, 21, 22, 23], buffer.sort
|
22
|
+
ensure
|
23
|
+
t&.kill
|
24
|
+
t&.join
|
18
25
|
end
|
19
26
|
|
20
27
|
def test_thread_join
|
@@ -23,11 +30,13 @@ class ThreadTest < MiniTest::Test
|
|
23
30
|
t = Thread.new { sleep 0.01; buffer << 4; :foo }
|
24
31
|
|
25
32
|
r = t.join
|
33
|
+
t = nil
|
26
34
|
|
27
|
-
assert_equal [1, 2, 3, 4], buffer
|
28
35
|
assert_equal :foo, r
|
36
|
+
assert_equal [1, 2, 3, 4], buffer
|
29
37
|
ensure
|
30
|
-
t
|
38
|
+
t&.kill
|
39
|
+
t&.join
|
31
40
|
end
|
32
41
|
|
33
42
|
def test_thread_join_with_timeout
|
@@ -36,6 +45,7 @@ class ThreadTest < MiniTest::Test
|
|
36
45
|
t = Thread.new { sleep 1; buffer << 4 }
|
37
46
|
t0 = Time.now
|
38
47
|
r = t.join(0.01)
|
48
|
+
t = nil
|
39
49
|
|
40
50
|
assert Time.now - t0 < 0.2
|
41
51
|
assert_equal [1, 2, 3], buffer
|
@@ -43,7 +53,8 @@ class ThreadTest < MiniTest::Test
|
|
43
53
|
ensure
|
44
54
|
# killing the thread will prevent stopping the sleep timer, as well as the
|
45
55
|
# thread's event selector, leading to a memory leak.
|
46
|
-
t&.kill
|
56
|
+
t&.kill
|
57
|
+
t&.join
|
47
58
|
end
|
48
59
|
|
49
60
|
def test_thread_await_alias_method
|
@@ -51,11 +62,13 @@ class ThreadTest < MiniTest::Test
|
|
51
62
|
spin { (1..3).each { |i| snooze; buffer << i } }
|
52
63
|
t = Thread.new { sleep 0.01; buffer << 4; :foo }
|
53
64
|
r = t.await
|
65
|
+
t = nil
|
54
66
|
|
55
67
|
assert_equal [1, 2, 3, 4], buffer
|
56
68
|
assert_equal :foo, r
|
57
69
|
ensure
|
58
|
-
t
|
70
|
+
t&.kill
|
71
|
+
t&.join
|
59
72
|
end
|
60
73
|
|
61
74
|
def test_join_race_condition_on_thread_spawning
|
@@ -64,27 +77,33 @@ class ThreadTest < MiniTest::Test
|
|
64
77
|
:foo
|
65
78
|
end
|
66
79
|
r = t.join
|
80
|
+
t = nil
|
67
81
|
assert_equal :foo, r
|
82
|
+
ensure
|
83
|
+
t&.kill
|
84
|
+
t&.join
|
68
85
|
end
|
69
86
|
|
70
87
|
def test_thread_uncaught_exception_propagation
|
71
|
-
|
72
|
-
sleep 1
|
73
|
-
end
|
74
|
-
snooze
|
75
|
-
t.kill
|
76
|
-
t.await
|
88
|
+
ready = Polyphony::Event.new
|
77
89
|
|
78
90
|
t = Thread.new do
|
91
|
+
ready.signal
|
92
|
+
sleep 0.01
|
79
93
|
raise 'foo'
|
80
94
|
end
|
81
95
|
e = nil
|
82
96
|
begin
|
83
|
-
|
97
|
+
ready.await
|
98
|
+
r = t.await
|
84
99
|
rescue Exception => e
|
85
100
|
end
|
101
|
+
t = nil
|
86
102
|
assert_kind_of RuntimeError, e
|
87
103
|
assert_equal 'foo', e.message
|
104
|
+
ensure
|
105
|
+
t&.kill
|
106
|
+
t&.join
|
88
107
|
end
|
89
108
|
|
90
109
|
def test_thread_inspect
|
@@ -101,9 +120,8 @@ class ThreadTest < MiniTest::Test
|
|
101
120
|
p e
|
102
121
|
puts e.backtrace.join("\n")
|
103
122
|
ensure
|
104
|
-
t
|
105
|
-
|
106
|
-
t.join
|
123
|
+
t&.kill
|
124
|
+
t&.join
|
107
125
|
end
|
108
126
|
|
109
127
|
def test_that_suspend_returns_immediately_if_no_watchers
|
@@ -112,14 +130,14 @@ class ThreadTest < MiniTest::Test
|
|
112
130
|
records << r if r[:event] =~ /^fiber_/
|
113
131
|
end
|
114
132
|
t.enable
|
115
|
-
|
133
|
+
Polyphony.trace(true)
|
116
134
|
|
117
135
|
suspend
|
118
136
|
t.disable
|
119
137
|
assert_equal [:fiber_switchpoint], records.map { |r| r[:event] }
|
120
138
|
ensure
|
121
139
|
t&.disable
|
122
|
-
|
140
|
+
Polyphony.trace(false)
|
123
141
|
end
|
124
142
|
|
125
143
|
def test_thread_child_fiber_termination
|
@@ -142,7 +160,11 @@ class ThreadTest < MiniTest::Test
|
|
142
160
|
assert_equal 2, t.main_fiber.children.size
|
143
161
|
t.kill
|
144
162
|
t.join
|
163
|
+
t = nil
|
145
164
|
|
146
165
|
assert_equal [:foo, :bar], buffer
|
166
|
+
ensure
|
167
|
+
t&.kill
|
168
|
+
t&.join
|
147
169
|
end
|
148
170
|
end
|
data/test/test_thread_pool.rb
CHANGED
@@ -25,7 +25,7 @@ class ThreadPoolTest < MiniTest::Test
|
|
25
25
|
threads = []
|
26
26
|
results = []
|
27
27
|
|
28
|
-
|
28
|
+
15.times do |i|
|
29
29
|
spin do
|
30
30
|
results << @pool.process do
|
31
31
|
threads << Thread.current
|
@@ -38,7 +38,7 @@ class ThreadPoolTest < MiniTest::Test
|
|
38
38
|
suspend
|
39
39
|
|
40
40
|
assert_equal @pool.size, threads.uniq.size
|
41
|
-
assert_equal (0..
|
41
|
+
assert_equal (0..14).map { |i| i * 10}, results.sort
|
42
42
|
end
|
43
43
|
|
44
44
|
def test_process_with_exception
|