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
@@ -10,7 +10,6 @@ module Concurrent
|
|
10
10
|
it_should_behave_like 'Thread Pool'
|
11
11
|
|
12
12
|
context '#initialize' do
|
13
|
-
|
14
13
|
it 'aliases Concurrent#new_cached_thread_pool' do
|
15
14
|
pool = Concurrent.new_cached_thread_pool
|
16
15
|
pool.should be_a(CachedThreadPool)
|
@@ -21,7 +20,7 @@ module Concurrent
|
|
21
20
|
context '#kill' do
|
22
21
|
|
23
22
|
it 'kills all threads' do
|
24
|
-
Thread.should_receive(:kill).
|
23
|
+
Thread.should_receive(:kill).exactly(5).times
|
25
24
|
pool = CachedThreadPool.new
|
26
25
|
5.times{ sleep(0.1); pool << proc{ sleep(1) } }
|
27
26
|
sleep(1)
|
@@ -109,17 +108,5 @@ module Concurrent
|
|
109
108
|
subject.instance_variable_get(:@collector).status.should be_false
|
110
109
|
end
|
111
110
|
end
|
112
|
-
|
113
|
-
context '#status' do
|
114
|
-
|
115
|
-
it 'returns an empty collection when the pool is empty' do
|
116
|
-
subject.status.should be_empty
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'returns one status object for each thread in the pool' do
|
120
|
-
3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
|
121
|
-
subject.status.length.should eq 3
|
122
|
-
end
|
123
|
-
end
|
124
111
|
end
|
125
112
|
end
|
@@ -4,12 +4,12 @@ module Concurrent
|
|
4
4
|
|
5
5
|
describe Defer do
|
6
6
|
|
7
|
-
before(:each) do
|
8
|
-
Defer.thread_pool = FixedThreadPool.new(1)
|
9
|
-
end
|
10
|
-
|
11
7
|
context '#initialize' do
|
12
8
|
|
9
|
+
before(:each) do
|
10
|
+
$GLOBAL_THREAD_POOL = FixedThreadPool.new(1)
|
11
|
+
end
|
12
|
+
|
13
13
|
it 'raises an exception if no block or operation given' do
|
14
14
|
lambda {
|
15
15
|
Defer.new
|
@@ -19,19 +19,23 @@ module Concurrent
|
|
19
19
|
it 'raises an exception if both a block and an operation given' do
|
20
20
|
lambda {
|
21
21
|
operation = proc{ nil }
|
22
|
-
Defer.new(
|
22
|
+
Defer.new(operation, nil, nil){ nil }
|
23
23
|
}.should raise_error(ArgumentError)
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'starts the thread if an operation is given' do
|
27
|
-
|
27
|
+
$GLOBAL_THREAD_POOL.should_receive(:post).once.with(any_args())
|
28
28
|
operation = proc{ nil }
|
29
|
-
Defer.new(
|
29
|
+
Defer.new(operation, nil, nil)
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'does not start the thread if neither a callback or errorback is given' do
|
33
|
-
|
34
|
-
Defer.new{ nil }
|
33
|
+
$GLOBAL_THREAD_POOL.should_not_receive(:post)
|
34
|
+
Defer.new(nil, nil, nil){ nil }
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'aliases Kernel#defer' do
|
38
|
+
defer{ nil }.should be_a(Defer)
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
@@ -52,14 +56,14 @@ module Concurrent
|
|
52
56
|
it 'raises an exception if an operation was provided at construction' do
|
53
57
|
lambda {
|
54
58
|
operation = proc{ nil }
|
55
|
-
Defer.new(
|
59
|
+
Defer.new(operation, nil, nil).then{|result| nil }
|
56
60
|
}.should raise_error(IllegalMethodCallError)
|
57
61
|
end
|
58
62
|
|
59
63
|
it 'raises an exception if a callback was provided at construction' do
|
60
64
|
lambda {
|
61
65
|
callback = proc{|result|nil }
|
62
|
-
Defer.new(callback
|
66
|
+
Defer.new(nil, callback, nil){ nil }.then{|result| nil }
|
63
67
|
}.should raise_error(IllegalMethodCallError)
|
64
68
|
end
|
65
69
|
|
@@ -86,14 +90,14 @@ module Concurrent
|
|
86
90
|
it 'raises an exception if an operation was provided at construction' do
|
87
91
|
lambda {
|
88
92
|
operation = proc{ nil }
|
89
|
-
Defer.new(
|
93
|
+
Defer.new(operation, nil, nil).rescue{|ex| nil }
|
90
94
|
}.should raise_error(IllegalMethodCallError)
|
91
95
|
end
|
92
96
|
|
93
97
|
it 'raises an exception if an errorback was provided at construction' do
|
94
98
|
lambda {
|
95
99
|
errorback = proc{|ex| nil }
|
96
|
-
Defer.new(
|
100
|
+
Defer.new(nil, nil, errorback){ nil }.rescue{|ex| nil }
|
97
101
|
}.should raise_error(IllegalMethodCallError)
|
98
102
|
end
|
99
103
|
|
@@ -119,14 +123,14 @@ module Concurrent
|
|
119
123
|
|
120
124
|
it 'starts the thread if not started' do
|
121
125
|
deferred = Defer.new{ nil }
|
122
|
-
|
126
|
+
$GLOBAL_THREAD_POOL.should_receive(:post).once.with(any_args())
|
123
127
|
deferred.go
|
124
128
|
end
|
125
129
|
|
126
130
|
it 'does nothing if called more than once' do
|
127
131
|
deferred = Defer.new{ nil }
|
128
132
|
deferred.go
|
129
|
-
|
133
|
+
$GLOBAL_THREAD_POOL.should_not_receive(:post)
|
130
134
|
deferred.go
|
131
135
|
end
|
132
136
|
|
@@ -134,8 +138,8 @@ module Concurrent
|
|
134
138
|
operation = proc{ nil }
|
135
139
|
callback = proc{|result| nil }
|
136
140
|
errorback = proc{|ex| nil }
|
137
|
-
deferred = Defer.new(
|
138
|
-
|
141
|
+
deferred = Defer.new(operation, callback, errorback)
|
142
|
+
$GLOBAL_THREAD_POOL.should_not_receive(:post)
|
139
143
|
deferred.go
|
140
144
|
end
|
141
145
|
end
|
@@ -2,251 +2,241 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
require 'concurrent/agent'
|
4
4
|
require 'concurrent/future'
|
5
|
-
require 'concurrent/goroutine'
|
6
5
|
require 'concurrent/promise'
|
7
6
|
|
8
|
-
|
7
|
+
module Concurrent
|
9
8
|
|
10
|
-
|
9
|
+
describe EventMachineDeferProxy do
|
11
10
|
|
12
|
-
|
11
|
+
subject { EventMachineDeferProxy.new }
|
13
12
|
|
14
|
-
|
13
|
+
context '#post' do
|
15
14
|
|
16
|
-
|
17
|
-
|
15
|
+
it 'proxies a call without arguments' do
|
16
|
+
@expected = false
|
17
|
+
EventMachine.run do
|
18
|
+
subject.post{ @expected = true }
|
19
|
+
sleep(0.1)
|
20
|
+
EventMachine.stop
|
21
|
+
end
|
22
|
+
@expected.should eq true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'proxies a call with arguments' do
|
26
|
+
@expected = []
|
27
|
+
EventMachine.run do
|
28
|
+
subject.post(1,2,3){|*args| @expected = args }
|
29
|
+
sleep(0.1)
|
30
|
+
EventMachine.stop
|
31
|
+
end
|
32
|
+
@expected.should eq [1,2,3]
|
18
33
|
end
|
19
34
|
|
20
|
-
|
35
|
+
it 'aliases #<<' do
|
36
|
+
@expected = false
|
37
|
+
EventMachine.run do
|
38
|
+
subject << proc{ @expected = true }
|
39
|
+
sleep(0.1)
|
40
|
+
EventMachine.stop
|
41
|
+
end
|
42
|
+
@expected.should eq true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'operation' do
|
47
|
+
|
48
|
+
context 'goroutine' do
|
49
|
+
|
50
|
+
it 'passes all arguments to the block' do
|
51
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
21
52
|
|
22
|
-
it 'proxies a call without arguments' do
|
23
|
-
@expected = false
|
24
53
|
EventMachine.run do
|
25
|
-
|
54
|
+
|
55
|
+
@expected = nil
|
56
|
+
go(1, 2, 3){|a, b, c| @expected = [c, b, a] }
|
26
57
|
sleep(0.1)
|
58
|
+
@expected.should eq [3, 2, 1]
|
59
|
+
|
27
60
|
EventMachine.stop
|
28
61
|
end
|
29
|
-
@expected.should eq true
|
30
62
|
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context Agent do
|
66
|
+
|
67
|
+
subject { Agent.new(0) }
|
68
|
+
|
69
|
+
it 'supports fulfillment' do
|
70
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
31
71
|
|
32
|
-
it 'proxies a call with arguments' do
|
33
|
-
@expected = []
|
34
72
|
EventMachine.run do
|
35
|
-
|
73
|
+
|
74
|
+
@expected = []
|
75
|
+
subject.post{ @expected << 1 }
|
76
|
+
subject.post{ @expected << 2 }
|
77
|
+
subject.post{ @expected << 3 }
|
36
78
|
sleep(0.1)
|
79
|
+
@expected.should eq [1,2,3]
|
80
|
+
|
37
81
|
EventMachine.stop
|
38
82
|
end
|
39
|
-
@expected.should eq [1,2,3]
|
40
83
|
end
|
41
84
|
|
42
|
-
it '
|
43
|
-
|
85
|
+
it 'supports validation' do
|
86
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
87
|
+
|
44
88
|
EventMachine.run do
|
45
|
-
|
89
|
+
|
90
|
+
@expected = nil
|
91
|
+
subject.validate{ @expected = 10; true }
|
92
|
+
subject.post{ nil }
|
46
93
|
sleep(0.1)
|
94
|
+
@expected.should eq 10
|
95
|
+
|
47
96
|
EventMachine.stop
|
48
97
|
end
|
49
|
-
@expected.should eq true
|
50
98
|
end
|
51
|
-
end
|
52
99
|
|
53
|
-
|
100
|
+
it 'supports rejection' do
|
101
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
54
102
|
|
55
|
-
|
103
|
+
EventMachine.run do
|
56
104
|
|
57
|
-
|
58
|
-
|
105
|
+
@expected = nil
|
106
|
+
subject.
|
107
|
+
on_error(StandardError){|ex| @expected = 1 }.
|
108
|
+
on_error(StandardError){|ex| @expected = 2 }.
|
109
|
+
on_error(StandardError){|ex| @expected = 3 }
|
110
|
+
subject.post{ raise StandardError }
|
111
|
+
sleep(0.1)
|
112
|
+
@expected.should eq 1
|
59
113
|
|
60
|
-
EventMachine.
|
114
|
+
EventMachine.stop
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
61
118
|
|
62
|
-
|
63
|
-
go(1, 2, 3){|a, b, c| @expected = [c, b, a] }
|
64
|
-
sleep(0.1)
|
65
|
-
@expected.should eq [3, 2, 1]
|
119
|
+
context Future do
|
66
120
|
|
67
|
-
|
121
|
+
it 'supports fulfillment' do
|
122
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
123
|
+
|
124
|
+
EventMachine.run do
|
125
|
+
|
126
|
+
@a = @b = @c = nil
|
127
|
+
f = Future.new(1, 2, 3) do |a, b, c|
|
128
|
+
@a, @b, @c = a, b, c
|
68
129
|
end
|
130
|
+
sleep(0.1)
|
131
|
+
[@a, @b, @c].should eq [1, 2, 3]
|
132
|
+
|
133
|
+
sleep(0.1)
|
134
|
+
EventMachine.stop
|
69
135
|
end
|
70
136
|
end
|
137
|
+
end
|
71
138
|
|
72
|
-
|
73
|
-
|
74
|
-
subject { Agent.new(0) }
|
139
|
+
context Promise do
|
75
140
|
|
76
|
-
|
77
|
-
Agent.thread_pool = EventMachineDeferProxy.new
|
78
|
-
end
|
141
|
+
context 'fulfillment' do
|
79
142
|
|
80
|
-
it '
|
143
|
+
it 'passes all arguments to the first promise in the chain' do
|
144
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
81
145
|
|
82
146
|
EventMachine.run do
|
83
147
|
|
84
|
-
@
|
85
|
-
|
86
|
-
|
87
|
-
|
148
|
+
@a = @b = @c = nil
|
149
|
+
p = Promise.new(1, 2, 3) do |a, b, c|
|
150
|
+
@a, @b, @c = a, b, c
|
151
|
+
end
|
88
152
|
sleep(0.1)
|
89
|
-
@
|
153
|
+
[@a, @b, @c].should eq [1, 2, 3]
|
90
154
|
|
155
|
+
sleep(0.1)
|
91
156
|
EventMachine.stop
|
92
157
|
end
|
93
158
|
end
|
94
159
|
|
95
|
-
it '
|
160
|
+
it 'passes the result of each block to all its children' do
|
161
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
96
162
|
|
97
163
|
EventMachine.run do
|
98
|
-
|
99
164
|
@expected = nil
|
100
|
-
|
101
|
-
subject.post{ nil }
|
165
|
+
Promise.new(10){|a| a * 2 }.then{|result| @expected = result}
|
102
166
|
sleep(0.1)
|
103
|
-
@expected.should eq
|
167
|
+
@expected.should eq 20
|
104
168
|
|
169
|
+
sleep(0.1)
|
105
170
|
EventMachine.stop
|
106
171
|
end
|
107
172
|
end
|
108
173
|
|
109
|
-
it '
|
174
|
+
it 'sets the promise value to the result if its block' do
|
175
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
110
176
|
|
111
177
|
EventMachine.run do
|
112
178
|
|
113
|
-
|
114
|
-
subject.
|
115
|
-
on_error(StandardError){|ex| @expected = 1 }.
|
116
|
-
on_error(StandardError){|ex| @expected = 2 }.
|
117
|
-
on_error(StandardError){|ex| @expected = 3 }
|
118
|
-
subject.post{ raise StandardError }
|
179
|
+
p = Promise.new(10){|a| a * 2 }.then{|result| result * 2}
|
119
180
|
sleep(0.1)
|
120
|
-
|
181
|
+
p.value.should eq 40
|
121
182
|
|
183
|
+
sleep(0.1)
|
122
184
|
EventMachine.stop
|
123
185
|
end
|
124
186
|
end
|
125
187
|
end
|
126
188
|
|
127
|
-
context
|
128
|
-
|
129
|
-
before(:each) do
|
130
|
-
Future.thread_pool = EventMachineDeferProxy.new
|
131
|
-
end
|
189
|
+
context 'rejection' do
|
132
190
|
|
133
|
-
it '
|
191
|
+
it 'sets the promise reason and error on exception' do
|
192
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
134
193
|
|
135
194
|
EventMachine.run do
|
136
195
|
|
137
|
-
|
138
|
-
f = Future.new(1, 2, 3) do |a, b, c|
|
139
|
-
@a, @b, @c = a, b, c
|
140
|
-
end
|
196
|
+
p = Promise.new{ raise StandardError.new('Boom!') }
|
141
197
|
sleep(0.1)
|
142
|
-
|
198
|
+
p.reason.should be_a(Exception)
|
199
|
+
p.reason.should.to_s =~ /Boom!/
|
200
|
+
p.should be_rejected
|
143
201
|
|
144
202
|
sleep(0.1)
|
145
203
|
EventMachine.stop
|
146
204
|
end
|
147
205
|
end
|
148
|
-
end
|
149
|
-
|
150
|
-
context Promise do
|
151
|
-
|
152
|
-
before(:each) do
|
153
|
-
Promise.thread_pool = EventMachineDeferProxy.new
|
154
|
-
end
|
155
|
-
|
156
|
-
context 'fulfillment' do
|
157
206
|
|
158
|
-
|
159
|
-
|
160
|
-
EventMachine.run do
|
161
|
-
|
162
|
-
@a = @b = @c = nil
|
163
|
-
p = Promise.new(1, 2, 3) do |a, b, c|
|
164
|
-
@a, @b, @c = a, b, c
|
165
|
-
end
|
166
|
-
sleep(0.1)
|
167
|
-
[@a, @b, @c].should eq [1, 2, 3]
|
168
|
-
|
169
|
-
sleep(0.1)
|
170
|
-
EventMachine.stop
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
it 'passes the result of each block to all its children' do
|
175
|
-
|
176
|
-
EventMachine.run do
|
177
|
-
@expected = nil
|
178
|
-
Promise.new(10){|a| a * 2 }.then{|result| @expected = result}
|
179
|
-
sleep(0.1)
|
180
|
-
@expected.should eq 20
|
181
|
-
|
182
|
-
sleep(0.1)
|
183
|
-
EventMachine.stop
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
it 'sets the promise value to the result if its block' do
|
207
|
+
it 'calls the first exception block with a matching class' do
|
208
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
188
209
|
|
189
|
-
|
210
|
+
EventMachine.run do
|
190
211
|
|
191
|
-
|
192
|
-
|
193
|
-
|
212
|
+
@expected = nil
|
213
|
+
Promise.new{ raise StandardError }.
|
214
|
+
on_error(StandardError){|ex| @expected = 1 }.
|
215
|
+
on_error(StandardError){|ex| @expected = 2 }.
|
216
|
+
on_error(StandardError){|ex| @expected = 3 }
|
217
|
+
sleep(0.1)
|
218
|
+
@expected.should eq 1
|
194
219
|
|
195
|
-
|
196
|
-
|
197
|
-
end
|
220
|
+
sleep(0.1)
|
221
|
+
EventMachine.stop
|
198
222
|
end
|
199
223
|
end
|
200
224
|
|
201
|
-
|
202
|
-
|
203
|
-
it 'sets the promise reason and error on exception' do
|
204
|
-
|
205
|
-
EventMachine.run do
|
206
|
-
|
207
|
-
p = Promise.new{ raise StandardError.new('Boom!') }
|
208
|
-
sleep(0.1)
|
209
|
-
p.reason.should be_a(Exception)
|
210
|
-
p.reason.should.to_s =~ /Boom!/
|
211
|
-
p.should be_rejected
|
212
|
-
|
213
|
-
sleep(0.1)
|
214
|
-
EventMachine.stop
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
it 'calls the first exception block with a matching class' do
|
219
|
-
|
220
|
-
EventMachine.run do
|
221
|
-
|
222
|
-
@expected = nil
|
223
|
-
Promise.new{ raise StandardError }.
|
224
|
-
on_error(StandardError){|ex| @expected = 1 }.
|
225
|
-
on_error(StandardError){|ex| @expected = 2 }.
|
226
|
-
on_error(StandardError){|ex| @expected = 3 }
|
227
|
-
sleep(0.1)
|
228
|
-
@expected.should eq 1
|
229
|
-
|
230
|
-
sleep(0.1)
|
231
|
-
EventMachine.stop
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'passes the exception object to the matched block' do
|
225
|
+
it 'passes the exception object to the matched block' do
|
226
|
+
$GLOBAL_THREAD_POOL = EventMachineDeferProxy.new
|
236
227
|
|
237
|
-
|
228
|
+
EventMachine.run do
|
238
229
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
230
|
+
@expected = nil
|
231
|
+
Promise.new{ raise StandardError }.
|
232
|
+
on_error(ArgumentError){|ex| @expected = ex }.
|
233
|
+
on_error(LoadError){|ex| @expected = ex }.
|
234
|
+
on_error(Exception){|ex| @expected = ex }
|
235
|
+
sleep(0.1)
|
236
|
+
@expected.should be_a(StandardError)
|
246
237
|
|
247
|
-
|
248
|
-
|
249
|
-
end
|
238
|
+
sleep(0.1)
|
239
|
+
EventMachine.stop
|
250
240
|
end
|
251
241
|
end
|
252
242
|
end
|