concurrent-ruby 0.1.1.pre.5 → 0.1.1
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/README.md +1 -48
- data/lib/concurrent.rb +0 -6
- data/lib/concurrent/agent.rb +40 -19
- data/lib/concurrent/cached_thread_pool.rb +11 -10
- data/lib/concurrent/defer.rb +12 -8
- data/lib/concurrent/fixed_thread_pool.rb +6 -12
- data/lib/concurrent/future.rb +20 -8
- data/lib/concurrent/global_thread_pool.rb +0 -13
- data/lib/concurrent/goroutine.rb +1 -5
- data/lib/concurrent/obligation.rb +64 -10
- data/lib/concurrent/promise.rb +60 -38
- data/lib/concurrent/thread_pool.rb +5 -16
- data/lib/concurrent/utilities.rb +0 -8
- data/lib/concurrent/version.rb +1 -1
- data/md/defer.md +4 -4
- data/md/promise.md +0 -2
- data/md/thread_pool.md +0 -27
- data/spec/concurrent/agent_spec.rb +27 -8
- data/spec/concurrent/cached_thread_pool_spec.rb +1 -14
- data/spec/concurrent/defer_spec.rb +21 -17
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +149 -159
- data/spec/concurrent/fixed_thread_pool_spec.rb +3 -2
- data/spec/concurrent/future_spec.rb +10 -3
- data/spec/concurrent/goroutine_spec.rb +0 -15
- data/spec/concurrent/obligation_shared.rb +2 -16
- data/spec/concurrent/promise_spec.rb +13 -15
- data/spec/concurrent/thread_pool_shared.rb +5 -5
- data/spec/concurrent/utilities_spec.rb +1 -30
- data/spec/spec_helper.rb +0 -25
- metadata +7 -28
- data/lib/concurrent/executor.rb +0 -95
- data/lib/concurrent/functions.rb +0 -120
- data/lib/concurrent/null_thread_pool.rb +0 -22
- data/lib/concurrent/reactor.rb +0 -161
- data/lib/concurrent/reactor/drb_async_demux.rb +0 -74
- data/lib/concurrent/reactor/tcp_sync_demux.rb +0 -98
- data/md/executor.md +0 -176
- data/spec/concurrent/executor_spec.rb +0 -200
- data/spec/concurrent/functions_spec.rb +0 -217
- data/spec/concurrent/global_thread_pool_spec.rb +0 -38
- data/spec/concurrent/null_thread_pool_spec.rb +0 -54
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +0 -12
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +0 -12
- data/spec/concurrent/reactor_spec.rb +0 -351
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe UsesGlobalThreadPool do
|
6
|
-
|
7
|
-
before(:each) do
|
8
|
-
$GLOBAL_THREAD_POOL = FixedThreadPool.new(1)
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'defaults to the global thread pool' do
|
12
|
-
clazz = Class.new{ include UsesGlobalThreadPool }
|
13
|
-
clazz.thread_pool.should eq $GLOBAL_THREAD_POOL
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'sets and gets the thread pool for the class' do
|
17
|
-
pool = NullThreadPool.new
|
18
|
-
clazz = Class.new{ include UsesGlobalThreadPool }
|
19
|
-
|
20
|
-
clazz.thread_pool = pool
|
21
|
-
clazz.thread_pool.should eq pool
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'gives each class its own thread pool' do
|
25
|
-
clazz1 = Class.new{ include UsesGlobalThreadPool }
|
26
|
-
clazz2 = Class.new{ include UsesGlobalThreadPool }
|
27
|
-
clazz3 = Class.new{ include UsesGlobalThreadPool }
|
28
|
-
|
29
|
-
clazz1.thread_pool = FixedThreadPool.new(1)
|
30
|
-
clazz2.thread_pool = CachedThreadPool.new
|
31
|
-
clazz3.thread_pool = NullThreadPool.new
|
32
|
-
|
33
|
-
clazz1.thread_pool.should_not eq clazz2.thread_pool
|
34
|
-
clazz2.thread_pool.should_not eq clazz3.thread_pool
|
35
|
-
clazz3.thread_pool.should_not eq clazz1.thread_pool
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'concurrent/goroutine'
|
4
|
-
|
5
|
-
module Concurrent
|
6
|
-
|
7
|
-
describe NullThreadPool do
|
8
|
-
|
9
|
-
subject { NullThreadPool.new }
|
10
|
-
|
11
|
-
after(:all) do
|
12
|
-
$GLOBAL_THREAD_POOL = FixedThreadPool.new(1)
|
13
|
-
end
|
14
|
-
|
15
|
-
context '#post' do
|
16
|
-
|
17
|
-
it 'proxies a call without arguments' do
|
18
|
-
Thread.should_receive(:new).with(no_args())
|
19
|
-
$GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
|
20
|
-
subject.post{ nil }
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'proxies a call with arguments' do
|
24
|
-
Thread.should_receive(:new).with(1,2,3)
|
25
|
-
$GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
|
26
|
-
subject.post(1,2,3){ nil }
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'aliases #<<' do
|
30
|
-
Thread.should_receive(:new).with(no_args())
|
31
|
-
$GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
|
32
|
-
subject << proc{ nil }
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context 'operation' do
|
37
|
-
|
38
|
-
context 'goroutine' do
|
39
|
-
|
40
|
-
it 'gets a new thread' do
|
41
|
-
$GLOBAL_THREAD_POOL = subject
|
42
|
-
|
43
|
-
t = Thread.new{ nil }
|
44
|
-
|
45
|
-
Thread.should_receive(:new).with(no_args()).and_return(t)
|
46
|
-
go{ nil }
|
47
|
-
|
48
|
-
Thread.should_receive(:new).with(1,2,3).and_return(t)
|
49
|
-
go(1,2,3){ nil }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,351 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe Reactor do
|
6
|
-
|
7
|
-
let(:sync_demux) do
|
8
|
-
Class.new {
|
9
|
-
def initialize
|
10
|
-
@running = false
|
11
|
-
@queue = Queue.new
|
12
|
-
end
|
13
|
-
def start() @running = true; end
|
14
|
-
def stop
|
15
|
-
@queue.push(:stop)
|
16
|
-
@running = false
|
17
|
-
end
|
18
|
-
def stopped?() return ! @running; end
|
19
|
-
def accept()
|
20
|
-
event = @queue.pop
|
21
|
-
if event == :stop
|
22
|
-
return nil
|
23
|
-
else
|
24
|
-
return Reactor::EventContext.new(event)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
def respond(result, message) return [result, message]; end
|
28
|
-
def close() nil; end
|
29
|
-
def send(event) @queue.push(event) end
|
30
|
-
}.new
|
31
|
-
end
|
32
|
-
|
33
|
-
let(:async_demux) do
|
34
|
-
Class.new {
|
35
|
-
def initialize() @running = false; end
|
36
|
-
def start() @running = true; end
|
37
|
-
def stop() @running = false; end
|
38
|
-
def stopped?() return ! @running; end
|
39
|
-
def set_reactor(reactor) @reactor = reactor; end
|
40
|
-
def send(event) @reactor.handle(event); end
|
41
|
-
}.new
|
42
|
-
end
|
43
|
-
|
44
|
-
context '#initialize' do
|
45
|
-
|
46
|
-
it 'raises an exception when the demux is not valid' do
|
47
|
-
lambda {
|
48
|
-
Reactor.new('bogus demux')
|
49
|
-
}.should raise_error(ArgumentError)
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'sets the initial state to not running' do
|
53
|
-
Reactor.new.should_not be_running
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context '#running?' do
|
58
|
-
|
59
|
-
it 'returns true when the reactor is running' do
|
60
|
-
reactor = Reactor.new
|
61
|
-
Thread.new{ reactor.start }
|
62
|
-
sleep(0.1)
|
63
|
-
reactor.should be_running
|
64
|
-
reactor.stop
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'returns true when the reactor is stopped' do
|
68
|
-
reactor = Reactor.new
|
69
|
-
Thread.new{ reactor.start }
|
70
|
-
sleep(0.1)
|
71
|
-
reactor.stop
|
72
|
-
sleep(0.1)
|
73
|
-
reactor.should_not be_running
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context '#add_handler' do
|
78
|
-
|
79
|
-
it 'raises an exception is the event name is reserved' do
|
80
|
-
reactor = Reactor.new
|
81
|
-
lambda {
|
82
|
-
reactor.add_handler(Reactor::RESERVED_EVENTS.first){ nil }
|
83
|
-
}.should raise_error(ArgumentError)
|
84
|
-
end
|
85
|
-
|
86
|
-
it 'raises an exception if no block is given' do
|
87
|
-
reactor = Reactor.new
|
88
|
-
lambda {
|
89
|
-
reactor.add_handler('no block given')
|
90
|
-
}.should raise_error(ArgumentError)
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'returns true if the handler is added' do
|
94
|
-
reactor = Reactor.new
|
95
|
-
reactor.add_handler('good'){ nil }.should be_true
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
context '#remove_handler' do
|
100
|
-
|
101
|
-
it 'returns true if the handler is found and removed' do
|
102
|
-
reactor = Reactor.new
|
103
|
-
reactor.add_handler('good'){ nil }
|
104
|
-
reactor.remove_handler('good').should be_true
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'returns false if the handler is not found' do
|
108
|
-
reactor = Reactor.new
|
109
|
-
reactor.remove_handler('not found').should be_false
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context '#stop_on_signal' do
|
114
|
-
|
115
|
-
it 'traps each valid signal' do
|
116
|
-
Signal.should_receive(:trap).with('USR1')
|
117
|
-
Signal.should_receive(:trap).with('USR2')
|
118
|
-
reactor = Reactor.new
|
119
|
-
reactor.stop_on_signal('USR1', 'USR2')
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'raises an exception if given an invalid signal' do
|
123
|
-
if mri?
|
124
|
-
reactor = Reactor.new
|
125
|
-
lambda {
|
126
|
-
reactor.stop_on_signal('BOGUS')
|
127
|
-
}.should raise_error(ArgumentError)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
it 'stops the reactor when it receives a trapped signal' do
|
132
|
-
reactor = Reactor.new
|
133
|
-
reactor.stop_on_signal('USR1')
|
134
|
-
reactor.should_receive(:stop).with(no_args())
|
135
|
-
Process.kill('USR1', Process.pid)
|
136
|
-
sleep(0.1)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
context '#handle' do
|
141
|
-
|
142
|
-
it 'raises an exception if the demux is synchronous' do
|
143
|
-
reactor = Reactor.new(sync_demux)
|
144
|
-
lambda {
|
145
|
-
reactor.handle('event')
|
146
|
-
}.should raise_error(NotImplementedError)
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'returns :stopped if the reactor is not running' do
|
150
|
-
reactor = Reactor.new
|
151
|
-
reactor.handle('event').first.should eq :stopped
|
152
|
-
end
|
153
|
-
|
154
|
-
it 'returns :ok and the block result on success' do
|
155
|
-
reactor = Reactor.new
|
156
|
-
reactor.add_handler(:event){ 10 }
|
157
|
-
Thread.new{ reactor.start }
|
158
|
-
sleep(0.1)
|
159
|
-
result = reactor.handle(:event)
|
160
|
-
result.first.should eq :ok
|
161
|
-
result.last.should eq 10
|
162
|
-
reactor.stop
|
163
|
-
end
|
164
|
-
|
165
|
-
it 'returns :ex and the exception on failure' do
|
166
|
-
reactor = Reactor.new
|
167
|
-
reactor.add_handler(:event){ raise StandardError }
|
168
|
-
Thread.new{ reactor.start }
|
169
|
-
sleep(0.1)
|
170
|
-
result = reactor.handle(:event)
|
171
|
-
result.first.should eq :ex
|
172
|
-
result.last.should be_a(StandardError)
|
173
|
-
reactor.stop
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'returns :noop when there is no handler' do
|
177
|
-
reactor = Reactor.new
|
178
|
-
Thread.new{ reactor.start }
|
179
|
-
sleep(0.1)
|
180
|
-
result = reactor.handle(:event)
|
181
|
-
result.first.should eq :noop
|
182
|
-
reactor.stop
|
183
|
-
end
|
184
|
-
|
185
|
-
it 'triggers handlers added after the reactor is started' do
|
186
|
-
@expected = false
|
187
|
-
reactor = Reactor.new
|
188
|
-
Thread.new{ reactor.start }
|
189
|
-
sleep(0.1)
|
190
|
-
reactor.add_handler(:event){ @expected = true }
|
191
|
-
reactor.handle(:event)
|
192
|
-
@expected.should be_true
|
193
|
-
reactor.stop
|
194
|
-
end
|
195
|
-
|
196
|
-
it 'does not trigger an event that was removed' do
|
197
|
-
@expected = false
|
198
|
-
reactor = Reactor.new
|
199
|
-
reactor.add_handler(:event){ @expected = true }
|
200
|
-
reactor.remove_handler(:event)
|
201
|
-
Thread.new{ reactor.start }
|
202
|
-
sleep(0.1)
|
203
|
-
reactor.handle(:event)
|
204
|
-
@expected.should be_false
|
205
|
-
reactor.stop
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
context '#start' do
|
210
|
-
|
211
|
-
it 'raises an exception if the reactor is already running' do
|
212
|
-
reactor = Reactor.new
|
213
|
-
Thread.new{ reactor.start }
|
214
|
-
sleep(0.1)
|
215
|
-
lambda {
|
216
|
-
reactor.start
|
217
|
-
}.should raise_error(StandardError)
|
218
|
-
reactor.stop
|
219
|
-
end
|
220
|
-
|
221
|
-
it 'starts the reactor if it is not running' do
|
222
|
-
reactor = Reactor.new(async_demux)
|
223
|
-
reactor.should_receive(:run_async).with(no_args())
|
224
|
-
Thread.new{ reactor.start }
|
225
|
-
sleep(0.1)
|
226
|
-
reactor.should be_running
|
227
|
-
reactor.stop
|
228
|
-
|
229
|
-
reactor = Reactor.new(sync_demux)
|
230
|
-
reactor.should_receive(:run_sync).with(no_args())
|
231
|
-
Thread.new{ reactor.start }
|
232
|
-
sleep(0.1)
|
233
|
-
reactor.should be_running
|
234
|
-
reactor.stop
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
context '#stop' do
|
239
|
-
|
240
|
-
it 'returns if the reactor is not running' do
|
241
|
-
reactor = Reactor.new
|
242
|
-
reactor.stop.should be_true
|
243
|
-
end
|
244
|
-
|
245
|
-
it 'stops the reactor when running and synchronous' do
|
246
|
-
reactor = Reactor.new(sync_demux)
|
247
|
-
Thread.new{ sleep(0.1); reactor.stop }
|
248
|
-
Thread.pass
|
249
|
-
reactor.start
|
250
|
-
end
|
251
|
-
|
252
|
-
it 'stops the reactor when running and asynchronous' do
|
253
|
-
reactor = Reactor.new(async_demux)
|
254
|
-
Thread.new{ sleep(0.1); reactor.stop }
|
255
|
-
Thread.pass
|
256
|
-
reactor.start
|
257
|
-
end
|
258
|
-
|
259
|
-
it 'stops the reactor when running without a demux' do
|
260
|
-
reactor = Reactor.new
|
261
|
-
Thread.new{ sleep(0.1); reactor.stop }
|
262
|
-
Thread.pass
|
263
|
-
reactor.start
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
specify 'synchronous demultiplexing' do
|
268
|
-
|
269
|
-
demux = sync_demux
|
270
|
-
reactor = Concurrent::Reactor.new(demux)
|
271
|
-
|
272
|
-
reactor.should_not be_running
|
273
|
-
|
274
|
-
reactor.add_handler(:foo){ 'Foo' }
|
275
|
-
reactor.add_handler(:bar){ 'Bar' }
|
276
|
-
reactor.add_handler(:baz){ 'Baz' }
|
277
|
-
reactor.add_handler(:fubar){ raise StandardError.new('Boom!') }
|
278
|
-
|
279
|
-
reactor.stop_on_signal('USR1')
|
280
|
-
|
281
|
-
demux.should_receive(:respond).with(:ok, 'Foo')
|
282
|
-
demux.send(:foo)
|
283
|
-
|
284
|
-
t = Thread.new do
|
285
|
-
reactor.start
|
286
|
-
end
|
287
|
-
t.abort_on_exception = true
|
288
|
-
sleep(0.1)
|
289
|
-
|
290
|
-
reactor.should be_running
|
291
|
-
|
292
|
-
demux.should_receive(:respond).with(:ok, 'Bar')
|
293
|
-
demux.should_receive(:respond).with(:ok, 'Baz')
|
294
|
-
demux.should_receive(:respond).with(:noop, anything())
|
295
|
-
demux.should_receive(:respond).with(:ex, anything())
|
296
|
-
|
297
|
-
demux.send(:bar)
|
298
|
-
demux.send(:baz)
|
299
|
-
demux.send(:bogus)
|
300
|
-
demux.send(:fubar)
|
301
|
-
|
302
|
-
reactor.should be_running
|
303
|
-
|
304
|
-
Process.kill('USR1', Process.pid)
|
305
|
-
sleep(0.1)
|
306
|
-
|
307
|
-
demux.should_not_receive(:respond).with(:foo, anything())
|
308
|
-
demux.send(:foo)
|
309
|
-
reactor.should_not be_running
|
310
|
-
end
|
311
|
-
|
312
|
-
specify 'asynchronous demultiplexing' do
|
313
|
-
|
314
|
-
demux = async_demux
|
315
|
-
reactor = Concurrent::Reactor.new(demux)
|
316
|
-
|
317
|
-
reactor.should_not be_running
|
318
|
-
|
319
|
-
reactor.add_handler(:foo){ 'Foo' }
|
320
|
-
reactor.add_handler(:bar){ 'Bar' }
|
321
|
-
reactor.add_handler(:baz){ 'Baz' }
|
322
|
-
reactor.add_handler(:fubar){ raise StandardError.new('Boom!') }
|
323
|
-
|
324
|
-
reactor.stop_on_signal('USR2')
|
325
|
-
|
326
|
-
demux.send(:foo).first.should eq :stopped
|
327
|
-
|
328
|
-
t = Thread.new do
|
329
|
-
reactor.start
|
330
|
-
end
|
331
|
-
t.abort_on_exception = true
|
332
|
-
sleep(0.1)
|
333
|
-
|
334
|
-
reactor.should be_running
|
335
|
-
|
336
|
-
demux.send(:foo).should eq [:ok, 'Foo']
|
337
|
-
demux.send(:bar).should eq [:ok, 'Bar']
|
338
|
-
demux.send(:baz).should eq [:ok, 'Baz']
|
339
|
-
demux.send(:bogus).first.should eq :noop
|
340
|
-
demux.send(:fubar).first.should eq :ex
|
341
|
-
|
342
|
-
reactor.should be_running
|
343
|
-
|
344
|
-
Process.kill('USR2', Process.pid)
|
345
|
-
sleep(0.1)
|
346
|
-
|
347
|
-
demux.send(:foo).first.should eq :stopped
|
348
|
-
reactor.should_not be_running
|
349
|
-
end
|
350
|
-
end
|
351
|
-
end
|