concurrent-ruby 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +275 -275
  3. data/lib/concurrent.rb +28 -28
  4. data/lib/concurrent/agent.rb +114 -114
  5. data/lib/concurrent/cached_thread_pool.rb +131 -129
  6. data/lib/concurrent/defer.rb +65 -65
  7. data/lib/concurrent/event.rb +60 -60
  8. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  9. data/lib/concurrent/executor.rb +96 -95
  10. data/lib/concurrent/fixed_thread_pool.rb +99 -95
  11. data/lib/concurrent/functions.rb +120 -120
  12. data/lib/concurrent/future.rb +42 -42
  13. data/lib/concurrent/global_thread_pool.rb +16 -16
  14. data/lib/concurrent/goroutine.rb +29 -29
  15. data/lib/concurrent/null_thread_pool.rb +22 -22
  16. data/lib/concurrent/obligation.rb +67 -67
  17. data/lib/concurrent/promise.rb +174 -174
  18. data/lib/concurrent/reactor.rb +166 -166
  19. data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
  20. data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
  21. data/lib/concurrent/supervisor.rb +105 -100
  22. data/lib/concurrent/thread_pool.rb +76 -76
  23. data/lib/concurrent/utilities.rb +32 -32
  24. data/lib/concurrent/version.rb +3 -3
  25. data/lib/concurrent_ruby.rb +1 -1
  26. data/md/agent.md +123 -123
  27. data/md/defer.md +174 -174
  28. data/md/event.md +32 -32
  29. data/md/executor.md +187 -187
  30. data/md/future.md +83 -83
  31. data/md/goroutine.md +52 -52
  32. data/md/obligation.md +32 -32
  33. data/md/promise.md +227 -227
  34. data/md/thread_pool.md +224 -224
  35. data/spec/concurrent/agent_spec.rb +386 -386
  36. data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
  37. data/spec/concurrent/defer_spec.rb +195 -195
  38. data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
  39. data/spec/concurrent/event_spec.rb +134 -134
  40. data/spec/concurrent/executor_spec.rb +200 -200
  41. data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
  42. data/spec/concurrent/functions_spec.rb +217 -217
  43. data/spec/concurrent/future_spec.rb +108 -108
  44. data/spec/concurrent/global_thread_pool_spec.rb +38 -38
  45. data/spec/concurrent/goroutine_spec.rb +67 -67
  46. data/spec/concurrent/null_thread_pool_spec.rb +57 -54
  47. data/spec/concurrent/obligation_shared.rb +132 -132
  48. data/spec/concurrent/promise_spec.rb +312 -312
  49. data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
  50. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
  51. data/spec/concurrent/reactor_spec.rb +364 -364
  52. data/spec/concurrent/supervisor_spec.rb +269 -258
  53. data/spec/concurrent/thread_pool_shared.rb +204 -204
  54. data/spec/concurrent/utilities_spec.rb +74 -74
  55. data/spec/spec_helper.rb +32 -32
  56. metadata +20 -16
  57. checksums.yaml +0 -7
@@ -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,195 @@
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
+
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