concurrent-ruby 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -21
  3. data/README.md +276 -275
  4. data/lib/concurrent.rb +28 -28
  5. data/lib/concurrent/agent.rb +114 -114
  6. data/lib/concurrent/cached_thread_pool.rb +131 -131
  7. data/lib/concurrent/defer.rb +65 -65
  8. data/lib/concurrent/event.rb +60 -60
  9. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  10. data/lib/concurrent/executor.rb +96 -96
  11. data/lib/concurrent/fixed_thread_pool.rb +99 -99
  12. data/lib/concurrent/functions.rb +120 -120
  13. data/lib/concurrent/future.rb +42 -42
  14. data/lib/concurrent/global_thread_pool.rb +24 -16
  15. data/lib/concurrent/goroutine.rb +29 -29
  16. data/lib/concurrent/null_thread_pool.rb +22 -22
  17. data/lib/concurrent/obligation.rb +67 -67
  18. data/lib/concurrent/promise.rb +174 -174
  19. data/lib/concurrent/reactor.rb +166 -166
  20. data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
  21. data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
  22. data/lib/concurrent/supervisor.rb +105 -105
  23. data/lib/concurrent/thread_pool.rb +76 -76
  24. data/lib/concurrent/utilities.rb +32 -32
  25. data/lib/concurrent/version.rb +3 -3
  26. data/lib/concurrent_ruby.rb +1 -1
  27. data/md/agent.md +123 -123
  28. data/md/defer.md +174 -174
  29. data/md/event.md +32 -32
  30. data/md/executor.md +187 -187
  31. data/md/future.md +83 -83
  32. data/md/goroutine.md +52 -52
  33. data/md/obligation.md +32 -32
  34. data/md/promise.md +227 -227
  35. data/md/thread_pool.md +224 -224
  36. data/spec/concurrent/agent_spec.rb +390 -386
  37. data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
  38. data/spec/concurrent/defer_spec.rb +199 -195
  39. data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
  40. data/spec/concurrent/event_spec.rb +134 -134
  41. data/spec/concurrent/executor_spec.rb +200 -200
  42. data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
  43. data/spec/concurrent/functions_spec.rb +217 -217
  44. data/spec/concurrent/future_spec.rb +112 -108
  45. data/spec/concurrent/global_thread_pool_spec.rb +11 -38
  46. data/spec/concurrent/goroutine_spec.rb +67 -67
  47. data/spec/concurrent/null_thread_pool_spec.rb +57 -57
  48. data/spec/concurrent/obligation_shared.rb +132 -132
  49. data/spec/concurrent/promise_spec.rb +316 -312
  50. data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
  51. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
  52. data/spec/concurrent/reactor_spec.rb +364 -364
  53. data/spec/concurrent/supervisor_spec.rb +269 -269
  54. data/spec/concurrent/thread_pool_shared.rb +204 -204
  55. data/spec/concurrent/uses_global_thread_pool_shared.rb +64 -0
  56. data/spec/concurrent/utilities_spec.rb +74 -74
  57. data/spec/spec_helper.rb +32 -32
  58. metadata +17 -19
@@ -1,125 +1,125 @@
1
- require 'spec_helper'
2
- require_relative 'thread_pool_shared'
3
-
4
- module Concurrent
5
-
6
- describe CachedThreadPool do
7
-
8
- subject { CachedThreadPool.new }
9
-
10
- it_should_behave_like 'Thread Pool'
11
-
12
- context '#initialize' do
13
-
14
- it 'aliases Concurrent#new_cached_thread_pool' do
15
- pool = Concurrent.new_cached_thread_pool
16
- pool.should be_a(CachedThreadPool)
17
- pool.size.should eq 0
18
- end
19
- end
20
-
21
- context '#kill' do
22
-
23
- it 'kills all threads' do
24
- Thread.should_receive(:kill).at_least(5).times
25
- pool = CachedThreadPool.new
26
- 5.times{ sleep(0.1); pool << proc{ sleep(1) } }
27
- sleep(1)
28
- pool.kill
29
- sleep(0.1)
30
- end
31
- end
32
-
33
- context '#size' do
34
-
35
- it 'returns zero for a new thread pool' do
36
- subject.size.should eq 0
37
- end
38
-
39
- it 'returns the size of the subject when running' do
40
- 5.times{ sleep(0.1); subject << proc{ sleep(1) } }
41
- subject.size.should eq 5
42
- end
43
-
44
- it 'returns zero once shut down' do
45
- subject.shutdown
46
- subject.size.should eq 0
47
- end
48
- end
49
-
50
- context 'worker creation and caching' do
51
-
52
- it 'creates new workers when there are none available' do
53
- subject.size.should eq 0
54
- 5.times{ sleep(0.1); subject << proc{ sleep(1000) } }
55
- sleep(1)
56
- subject.size.should eq 5
57
- end
58
-
59
- it 'uses existing idle threads' do
60
- 5.times{ sleep(0.05); subject << proc{ sleep(0.5) } }
61
- sleep(1)
62
- 3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
63
- subject.size.should eq 5
64
- end
65
- end
66
-
67
- context 'garbage collection' do
68
-
69
- subject{ CachedThreadPool.new(gc_interval: 1, thread_idleime: 1) }
70
-
71
- it 'starts when the first thread is added to the pool' do
72
- subject.should_receive(:collect_garbage)
73
- subject << proc{ nil }
74
- sleep(0.1)
75
- end
76
-
77
- it 'removes from pool any thread that has been idle too long' do
78
- subject << proc{ nil }
79
- subject.size.should eq 1
80
- sleep(1.5)
81
- subject.size.should eq 0
82
- end
83
-
84
- it 'removed from pool any dead thread' do
85
- subject << proc{ raise StandardError }
86
- subject.size.should eq 1
87
- sleep(1.5)
88
- subject.size.should eq 0
89
- end
90
-
91
- it 'resets the working count appropriately' do
92
- subject << proc{ sleep(1000) }
93
- sleep(0.1)
94
- subject << proc{ raise StandardError }
95
- sleep(0.1)
96
- subject << proc{ nil }
97
-
98
- sleep(0.1)
99
- subject.working.should eq 2
100
-
101
- sleep(1.5)
102
- subject.working.should eq 1
103
- end
104
-
105
- it 'stops collection when the pool size becomes zero' do
106
- 3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
107
- subject.instance_variable_get(:@collector).status.should eq 'sleep'
108
- sleep(1.5)
109
- subject.instance_variable_get(:@collector).status.should be_false
110
- end
111
- 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
- end
125
- end
1
+ require 'spec_helper'
2
+ require_relative 'thread_pool_shared'
3
+
4
+ module Concurrent
5
+
6
+ describe CachedThreadPool do
7
+
8
+ subject { CachedThreadPool.new }
9
+
10
+ it_should_behave_like 'Thread Pool'
11
+
12
+ context '#initialize' do
13
+
14
+ it 'aliases Concurrent#new_cached_thread_pool' do
15
+ pool = Concurrent.new_cached_thread_pool
16
+ pool.should be_a(CachedThreadPool)
17
+ pool.size.should eq 0
18
+ end
19
+ end
20
+
21
+ context '#kill' do
22
+
23
+ it 'kills all threads' do
24
+ Thread.should_receive(:kill).at_least(5).times
25
+ pool = CachedThreadPool.new
26
+ 5.times{ sleep(0.1); pool << proc{ sleep(1) } }
27
+ sleep(1)
28
+ pool.kill
29
+ sleep(0.1)
30
+ end
31
+ end
32
+
33
+ context '#size' do
34
+
35
+ it 'returns zero for a new thread pool' do
36
+ subject.size.should eq 0
37
+ end
38
+
39
+ it 'returns the size of the subject when running' do
40
+ 5.times{ sleep(0.1); subject << proc{ sleep(1) } }
41
+ subject.size.should eq 5
42
+ end
43
+
44
+ it 'returns zero once shut down' do
45
+ subject.shutdown
46
+ subject.size.should eq 0
47
+ end
48
+ end
49
+
50
+ context 'worker creation and caching' do
51
+
52
+ it 'creates new workers when there are none available' do
53
+ subject.size.should eq 0
54
+ 5.times{ sleep(0.1); subject << proc{ sleep(1000) } }
55
+ sleep(1)
56
+ subject.size.should eq 5
57
+ end
58
+
59
+ it 'uses existing idle threads' do
60
+ 5.times{ sleep(0.05); subject << proc{ sleep(0.5) } }
61
+ sleep(1)
62
+ 3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
63
+ subject.size.should eq 5
64
+ end
65
+ end
66
+
67
+ context 'garbage collection' do
68
+
69
+ subject{ CachedThreadPool.new(gc_interval: 1, thread_idleime: 1) }
70
+
71
+ it 'starts when the first thread is added to the pool' do
72
+ subject.should_receive(:collect_garbage)
73
+ subject << proc{ nil }
74
+ sleep(0.1)
75
+ end
76
+
77
+ it 'removes from pool any thread that has been idle too long' do
78
+ subject << proc{ nil }
79
+ subject.size.should eq 1
80
+ sleep(1.5)
81
+ subject.size.should eq 0
82
+ end
83
+
84
+ it 'removed from pool any dead thread' do
85
+ subject << proc{ raise StandardError }
86
+ subject.size.should eq 1
87
+ sleep(1.5)
88
+ subject.size.should eq 0
89
+ end
90
+
91
+ it 'resets the working count appropriately' do
92
+ subject << proc{ sleep(1000) }
93
+ sleep(0.1)
94
+ subject << proc{ raise StandardError }
95
+ sleep(0.1)
96
+ subject << proc{ nil }
97
+
98
+ sleep(0.1)
99
+ subject.working.should eq 2
100
+
101
+ sleep(1.5)
102
+ subject.working.should eq 1
103
+ end
104
+
105
+ it 'stops collection when the pool size becomes zero' do
106
+ 3.times{ sleep(0.1); subject << proc{ sleep(0.5) } }
107
+ subject.instance_variable_get(:@collector).status.should eq 'sleep'
108
+ sleep(1.5)
109
+ subject.instance_variable_get(:@collector).status.should be_false
110
+ end
111
+ 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
+ end
125
+ end
@@ -1,195 +1,199 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe Defer do
6
-
7
- before(:each) do
8
- Defer.thread_pool = FixedThreadPool.new(1)
9
- end
10
-
11
- context '#initialize' do
12
-
13
- it 'raises an exception if no block or operation given' do
14
- lambda {
15
- Defer.new
16
- }.should raise_error(ArgumentError)
17
- end
18
-
19
- it 'raises an exception if both a block and an operation given' do
20
- lambda {
21
- operation = proc{ nil }
22
- Defer.new(op: operation){ nil }
23
- }.should raise_error(ArgumentError)
24
- end
25
-
26
- it 'starts the thread if an operation is given' do
27
- Defer.thread_pool.should_receive(:post).once.with(any_args())
28
- operation = proc{ nil }
29
- Defer.new(op: operation)
30
- end
31
-
32
- it 'does not start the thread if neither a callback or errorback is given' do
33
- Defer.thread_pool.should_not_receive(:post)
34
- Defer.new{ nil }
35
- end
36
- end
37
-
38
- context '#then' do
39
-
40
- it 'raises an exception if no block given' do
41
- lambda {
42
- Defer.new{ nil }.then
43
- }.should raise_error(ArgumentError)
44
- end
45
-
46
- it 'raises an exception if called twice' do
47
- lambda {
48
- Defer.new{ nil }.then{|result| nil }.then{|result| nil }
49
- }.should raise_error(IllegalMethodCallError)
50
- end
51
-
52
- it 'raises an exception if an operation was provided at construction' do
53
- lambda {
54
- operation = proc{ nil }
55
- Defer.new(op: operation).then{|result| nil }
56
- }.should raise_error(IllegalMethodCallError)
57
- end
58
-
59
- it 'raises an exception if a callback was provided at construction' do
60
- lambda {
61
- callback = proc{|result|nil }
62
- Defer.new(callback: callback){ nil }.then{|result| nil }
63
- }.should raise_error(IllegalMethodCallError)
64
- end
65
-
66
- it 'returns self' do
67
- deferred = Defer.new{ nil }
68
- deferred.then{|result| nil }.should eq deferred
69
- end
70
- end
71
-
72
- context '#rescue' do
73
-
74
- it 'raises an exception if no block given' do
75
- lambda {
76
- Defer.new{ nil }.rescue
77
- }.should raise_error(ArgumentError)
78
- end
79
-
80
- it 'raises an exception if called twice' do
81
- lambda {
82
- Defer.new{ nil }.rescue{ nil }.rescue{ nil }
83
- }.should raise_error(IllegalMethodCallError)
84
- end
85
-
86
- it 'raises an exception if an operation was provided at construction' do
87
- lambda {
88
- operation = proc{ nil }
89
- Defer.new(op: operation).rescue{|ex| nil }
90
- }.should raise_error(IllegalMethodCallError)
91
- end
92
-
93
- it 'raises an exception if an errorback was provided at construction' do
94
- lambda {
95
- errorback = proc{|ex| nil }
96
- Defer.new(errorback: errorback){ nil }.rescue{|ex| nil }
97
- }.should raise_error(IllegalMethodCallError)
98
- end
99
-
100
- it 'returns self' do
101
- deferred = Defer.new{ nil }
102
- deferred.rescue{|ex| nil }.should eq deferred
103
- end
104
-
105
- it 'aliases #catch' do
106
- lambda {
107
- Defer.new{ nil }.catch{|ex| nil }
108
- }.should_not raise_error
109
- end
110
-
111
- it 'aliases #on_error' do
112
- lambda {
113
- Defer.new{ nil }.on_error{|ex| nil }
114
- }.should_not raise_error
115
- end
116
- end
117
-
118
- context '#go' do
119
-
120
- it 'starts the thread if not started' do
121
- deferred = Defer.new{ nil }
122
- Defer.thread_pool.should_receive(:post).once.with(any_args())
123
- deferred.go
124
- end
125
-
126
- it 'does nothing if called more than once' do
127
- deferred = Defer.new{ nil }
128
- deferred.go
129
- Defer.thread_pool.should_not_receive(:post)
130
- deferred.go
131
- end
132
-
133
- it 'does nothing if thread started at construction' do
134
- operation = proc{ nil }
135
- callback = proc{|result| nil }
136
- errorback = proc{|ex| nil }
137
- deferred = Defer.new(op: operation, callback: callback, errorback: errorback)
138
- Defer.thread_pool.should_not_receive(:post)
139
- deferred.go
140
- end
141
- end
142
-
143
- context 'fulfillment' do
144
-
145
- it 'runs the operation' do
146
- @expected = false
147
- Defer.new{ @expected = true }.go
148
- sleep(0.1)
149
- @expected.should be_true
150
- end
151
-
152
- it 'calls the callback when the operation is successful' do
153
- @expected = false
154
- Defer.new{ true }.then{|result| @expected = true }.go
155
- sleep(0.1)
156
- @expected.should be_true
157
- end
158
-
159
- it 'passes the result of the block to the callback' do
160
- @expected = false
161
- Defer.new{ 'w00t' }.then{|result| @expected = result }.go
162
- sleep(0.1)
163
- @expected.should eq 'w00t'
164
- end
165
-
166
- it 'does not call the errorback when the operation is successful' do
167
- @expected = true
168
- Defer.new{ nil }.rescue{|ex| @expected = false }.go
169
- sleep(0.1)
170
- @expected.should be_true
171
- end
172
-
173
- it 'calls the errorback if the operation throws an exception' do
174
- @expected = false
175
- Defer.new{ raise StandardError }.rescue{|ex| @expected = true }.go
176
- sleep(0.1)
177
- @expected.should be_true
178
- end
179
-
180
- it 'passes the exception object to the errorback' do
181
- @expected = nil
182
- Defer.new{ raise StandardError }.rescue{|ex| @expected = ex }.go
183
- sleep(0.1)
184
- @expected.should be_a(StandardError)
185
- end
186
-
187
- it 'does not call the callback when the operation fails' do
188
- @expected = true
189
- Defer.new{ raise StandardError }.then{|result| @expected = false }.go
190
- sleep(0.1)
191
- @expected.should be_true
192
- end
193
- end
194
- end
195
- end
1
+ require 'spec_helper'
2
+ require_relative 'uses_global_thread_pool_shared'
3
+
4
+ module Concurrent
5
+
6
+ describe Defer do
7
+
8
+ let!(:thread_pool_user){ Defer }
9
+ it_should_behave_like Concurrent::UsesGlobalThreadPool
10
+
11
+ before(:each) do
12
+ Defer.thread_pool = FixedThreadPool.new(1)
13
+ end
14
+
15
+ context '#initialize' do
16
+
17
+ it 'raises an exception if no block or operation given' do
18
+ lambda {
19
+ Defer.new
20
+ }.should raise_error(ArgumentError)
21
+ end
22
+
23
+ it 'raises an exception if both a block and an operation given' do
24
+ lambda {
25
+ operation = proc{ nil }
26
+ Defer.new(op: operation){ nil }
27
+ }.should raise_error(ArgumentError)
28
+ end
29
+
30
+ it 'starts the thread if an operation is given' do
31
+ Defer.thread_pool.should_receive(:post).once.with(any_args())
32
+ operation = proc{ nil }
33
+ Defer.new(op: operation)
34
+ end
35
+
36
+ it 'does not start the thread if neither a callback or errorback is given' do
37
+ Defer.thread_pool.should_not_receive(:post)
38
+ Defer.new{ nil }
39
+ end
40
+ end
41
+
42
+ context '#then' do
43
+
44
+ it 'raises an exception if no block given' do
45
+ lambda {
46
+ Defer.new{ nil }.then
47
+ }.should raise_error(ArgumentError)
48
+ end
49
+
50
+ it 'raises an exception if called twice' do
51
+ lambda {
52
+ Defer.new{ nil }.then{|result| nil }.then{|result| nil }
53
+ }.should raise_error(IllegalMethodCallError)
54
+ end
55
+
56
+ it 'raises an exception if an operation was provided at construction' do
57
+ lambda {
58
+ operation = proc{ nil }
59
+ Defer.new(op: operation).then{|result| nil }
60
+ }.should raise_error(IllegalMethodCallError)
61
+ end
62
+
63
+ it 'raises an exception if a callback was provided at construction' do
64
+ lambda {
65
+ callback = proc{|result|nil }
66
+ Defer.new(callback: callback){ nil }.then{|result| nil }
67
+ }.should raise_error(IllegalMethodCallError)
68
+ end
69
+
70
+ it 'returns self' do
71
+ deferred = Defer.new{ nil }
72
+ deferred.then{|result| nil }.should eq deferred
73
+ end
74
+ end
75
+
76
+ context '#rescue' do
77
+
78
+ it 'raises an exception if no block given' do
79
+ lambda {
80
+ Defer.new{ nil }.rescue
81
+ }.should raise_error(ArgumentError)
82
+ end
83
+
84
+ it 'raises an exception if called twice' do
85
+ lambda {
86
+ Defer.new{ nil }.rescue{ nil }.rescue{ nil }
87
+ }.should raise_error(IllegalMethodCallError)
88
+ end
89
+
90
+ it 'raises an exception if an operation was provided at construction' do
91
+ lambda {
92
+ operation = proc{ nil }
93
+ Defer.new(op: operation).rescue{|ex| nil }
94
+ }.should raise_error(IllegalMethodCallError)
95
+ end
96
+
97
+ it 'raises an exception if an errorback was provided at construction' do
98
+ lambda {
99
+ errorback = proc{|ex| nil }
100
+ Defer.new(errorback: errorback){ nil }.rescue{|ex| nil }
101
+ }.should raise_error(IllegalMethodCallError)
102
+ end
103
+
104
+ it 'returns self' do
105
+ deferred = Defer.new{ nil }
106
+ deferred.rescue{|ex| nil }.should eq deferred
107
+ end
108
+
109
+ it 'aliases #catch' do
110
+ lambda {
111
+ Defer.new{ nil }.catch{|ex| nil }
112
+ }.should_not raise_error
113
+ end
114
+
115
+ it 'aliases #on_error' do
116
+ lambda {
117
+ Defer.new{ nil }.on_error{|ex| nil }
118
+ }.should_not raise_error
119
+ end
120
+ end
121
+
122
+ context '#go' do
123
+
124
+ it 'starts the thread if not started' do
125
+ deferred = Defer.new{ nil }
126
+ Defer.thread_pool.should_receive(:post).once.with(any_args())
127
+ deferred.go
128
+ end
129
+
130
+ it 'does nothing if called more than once' do
131
+ deferred = Defer.new{ nil }
132
+ deferred.go
133
+ Defer.thread_pool.should_not_receive(:post)
134
+ deferred.go
135
+ end
136
+
137
+ it 'does nothing if thread started at construction' do
138
+ operation = proc{ nil }
139
+ callback = proc{|result| nil }
140
+ errorback = proc{|ex| nil }
141
+ deferred = Defer.new(op: operation, callback: callback, errorback: errorback)
142
+ Defer.thread_pool.should_not_receive(:post)
143
+ deferred.go
144
+ end
145
+ end
146
+
147
+ context 'fulfillment' do
148
+
149
+ it 'runs the operation' do
150
+ @expected = false
151
+ Defer.new{ @expected = true }.go
152
+ sleep(0.1)
153
+ @expected.should be_true
154
+ end
155
+
156
+ it 'calls the callback when the operation is successful' do
157
+ @expected = false
158
+ Defer.new{ true }.then{|result| @expected = true }.go
159
+ sleep(0.1)
160
+ @expected.should be_true
161
+ end
162
+
163
+ it 'passes the result of the block to the callback' do
164
+ @expected = false
165
+ Defer.new{ 'w00t' }.then{|result| @expected = result }.go
166
+ sleep(0.1)
167
+ @expected.should eq 'w00t'
168
+ end
169
+
170
+ it 'does not call the errorback when the operation is successful' do
171
+ @expected = true
172
+ Defer.new{ nil }.rescue{|ex| @expected = false }.go
173
+ sleep(0.1)
174
+ @expected.should be_true
175
+ end
176
+
177
+ it 'calls the errorback if the operation throws an exception' do
178
+ @expected = false
179
+ Defer.new{ raise StandardError }.rescue{|ex| @expected = true }.go
180
+ sleep(0.1)
181
+ @expected.should be_true
182
+ end
183
+
184
+ it 'passes the exception object to the errorback' do
185
+ @expected = nil
186
+ Defer.new{ raise StandardError }.rescue{|ex| @expected = ex }.go
187
+ sleep(0.1)
188
+ @expected.should be_a(StandardError)
189
+ end
190
+
191
+ it 'does not call the callback when the operation fails' do
192
+ @expected = true
193
+ Defer.new{ raise StandardError }.then{|result| @expected = false }.go
194
+ sleep(0.1)
195
+ @expected.should be_true
196
+ end
197
+ end
198
+ end
199
+ end