concurrent-ruby 0.1.1.pre.3 → 0.1.1.pre.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -21
  3. data/README.md +275 -279
  4. data/lib/concurrent.rb +27 -28
  5. data/lib/concurrent/agent.rb +114 -108
  6. data/lib/concurrent/cached_thread_pool.rb +129 -130
  7. data/lib/concurrent/defer.rb +65 -67
  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 +93 -95
  11. data/lib/concurrent/fixed_thread_pool.rb +95 -89
  12. data/lib/concurrent/functions.rb +120 -120
  13. data/lib/concurrent/future.rb +42 -47
  14. data/lib/concurrent/global_thread_pool.rb +16 -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 -166
  19. data/lib/concurrent/reactor.rb +161 -162
  20. data/lib/concurrent/reactor/drb_async_demux.rb +74 -74
  21. data/lib/concurrent/reactor/tcp_sync_demux.rb +98 -98
  22. data/lib/concurrent/thread_pool.rb +76 -69
  23. data/lib/concurrent/utilities.rb +32 -34
  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 +176 -176
  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 -380
  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 -253
  39. data/spec/concurrent/event_spec.rb +134 -134
  40. data/spec/concurrent/executor_spec.rb +184 -184
  41. data/spec/concurrent/fixed_thread_pool_spec.rb +83 -84
  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 +54 -54
  47. data/spec/concurrent/obligation_shared.rb +135 -121
  48. data/spec/concurrent/promise_spec.rb +312 -305
  49. data/spec/concurrent/reactor/drb_async_demux_spec.rb +12 -12
  50. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +12 -12
  51. data/spec/concurrent/reactor_spec.rb +351 -10
  52. data/spec/concurrent/thread_pool_shared.rb +209 -210
  53. data/spec/concurrent/utilities_spec.rb +74 -74
  54. data/spec/spec_helper.rb +44 -30
  55. metadata +11 -22
  56. data/lib/concurrent/smart_mutex.rb +0 -66
  57. data/spec/concurrent/smart_mutex_spec.rb +0 -234
@@ -1,134 +1,134 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe Event do
6
-
7
- subject{ Event.new }
8
-
9
- context '#initialize' do
10
-
11
- it 'sets the state to unset' do
12
- subject.should_not be_set
13
- end
14
- end
15
-
16
- context '#set?' do
17
-
18
- it 'returns true when the event has been set' do
19
- subject.set
20
- subject.should be_set
21
- end
22
-
23
- it 'returns false if the event is unset' do
24
- subject.reset
25
- subject.should_not be_set
26
- end
27
- end
28
-
29
- context '#set' do
30
-
31
- it 'triggers the event' do
32
- subject.reset
33
- @expected = false
34
- Thread.new{ subject.wait; @expected = true }
35
- sleep(0.1)
36
- subject.set
37
- sleep(0.1)
38
- @expected.should be_true
39
- end
40
-
41
- it 'sets the state to set' do
42
- subject.set
43
- subject.should be_set
44
- end
45
- end
46
-
47
- context '#reset' do
48
-
49
- it 'sets the state to unset' do
50
- subject.set
51
- subject.should be_set
52
- subject.reset
53
- subject.should_not be_set
54
- end
55
- end
56
-
57
- context '#pulse' do
58
-
59
- it 'triggers the event' do
60
- subject.reset
61
- @expected = false
62
- Thread.new{ subject.wait; @expected = true }
63
- sleep(0.1)
64
- subject.pulse
65
- sleep(0.1)
66
- @expected.should be_true
67
- end
68
-
69
- it 'sets the state to unset' do
70
- subject.pulse
71
- sleep(0.1)
72
- subject.should_not be_set
73
- end
74
- end
75
-
76
- context '#wait' do
77
-
78
- it 'returns immediately when the event has been set' do
79
- subject.reset
80
- @expected = false
81
- subject.set
82
- Thread.new{ subject.wait(1000); @expected = true}
83
- sleep(1)
84
- @expected.should be_true
85
- end
86
-
87
- it 'returns true once the event is set' do
88
- subject.set
89
- subject.wait.should be_true
90
- end
91
-
92
- it 'blocks indefinitely when the timer is nil' do
93
- subject.reset
94
- @expected = false
95
- Thread.new{ subject.wait; @expected = true}
96
- subject.set
97
- sleep(1)
98
- @expected.should be_true
99
- end
100
-
101
- it 'stops waiting when the timer expires' do
102
- subject.reset
103
- @expected = false
104
- Thread.new{ subject.wait(0.5); @expected = true}
105
- sleep(1)
106
- @expected.should be_true
107
- end
108
-
109
- it 'returns false when the timer expires' do
110
- subject.reset
111
- subject.wait(1).should be_false
112
- end
113
-
114
- it 'triggers multiple waiting threads' do
115
- subject.reset
116
- @expected = []
117
- 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
118
- subject.set
119
- sleep(1)
120
- @expected.length.should eq 5
121
- end
122
-
123
- it 'behaves appropriately if wait begins while #set is processing' do
124
- subject.reset
125
- @expected = []
126
- 5.times{ Thread.new{ subject.wait(5) } }
127
- subject.set
128
- 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
129
- sleep(1)
130
- @expected.length.should eq 5
131
- end
132
- end
133
- end
134
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe Event do
6
+
7
+ subject{ Event.new }
8
+
9
+ context '#initialize' do
10
+
11
+ it 'sets the state to unset' do
12
+ subject.should_not be_set
13
+ end
14
+ end
15
+
16
+ context '#set?' do
17
+
18
+ it 'returns true when the event has been set' do
19
+ subject.set
20
+ subject.should be_set
21
+ end
22
+
23
+ it 'returns false if the event is unset' do
24
+ subject.reset
25
+ subject.should_not be_set
26
+ end
27
+ end
28
+
29
+ context '#set' do
30
+
31
+ it 'triggers the event' do
32
+ subject.reset
33
+ @expected = false
34
+ Thread.new{ subject.wait; @expected = true }
35
+ sleep(0.1)
36
+ subject.set
37
+ sleep(0.1)
38
+ @expected.should be_true
39
+ end
40
+
41
+ it 'sets the state to set' do
42
+ subject.set
43
+ subject.should be_set
44
+ end
45
+ end
46
+
47
+ context '#reset' do
48
+
49
+ it 'sets the state to unset' do
50
+ subject.set
51
+ subject.should be_set
52
+ subject.reset
53
+ subject.should_not be_set
54
+ end
55
+ end
56
+
57
+ context '#pulse' do
58
+
59
+ it 'triggers the event' do
60
+ subject.reset
61
+ @expected = false
62
+ Thread.new{ subject.wait; @expected = true }
63
+ sleep(0.1)
64
+ subject.pulse
65
+ sleep(0.1)
66
+ @expected.should be_true
67
+ end
68
+
69
+ it 'sets the state to unset' do
70
+ subject.pulse
71
+ sleep(0.1)
72
+ subject.should_not be_set
73
+ end
74
+ end
75
+
76
+ context '#wait' do
77
+
78
+ it 'returns immediately when the event has been set' do
79
+ subject.reset
80
+ @expected = false
81
+ subject.set
82
+ Thread.new{ subject.wait(1000); @expected = true}
83
+ sleep(1)
84
+ @expected.should be_true
85
+ end
86
+
87
+ it 'returns true once the event is set' do
88
+ subject.set
89
+ subject.wait.should be_true
90
+ end
91
+
92
+ it 'blocks indefinitely when the timer is nil' do
93
+ subject.reset
94
+ @expected = false
95
+ Thread.new{ subject.wait; @expected = true}
96
+ subject.set
97
+ sleep(1)
98
+ @expected.should be_true
99
+ end
100
+
101
+ it 'stops waiting when the timer expires' do
102
+ subject.reset
103
+ @expected = false
104
+ Thread.new{ subject.wait(0.5); @expected = true}
105
+ sleep(1)
106
+ @expected.should be_true
107
+ end
108
+
109
+ it 'returns false when the timer expires' do
110
+ subject.reset
111
+ subject.wait(1).should be_false
112
+ end
113
+
114
+ it 'triggers multiple waiting threads' do
115
+ subject.reset
116
+ @expected = []
117
+ 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
118
+ subject.set
119
+ sleep(1)
120
+ @expected.length.should eq 5
121
+ end
122
+
123
+ it 'behaves appropriately if wait begins while #set is processing' do
124
+ subject.reset
125
+ @expected = []
126
+ 5.times{ Thread.new{ subject.wait(5) } }
127
+ subject.set
128
+ 5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
129
+ sleep(1)
130
+ @expected.length.should eq 5
131
+ end
132
+ end
133
+ end
134
+ end
@@ -1,184 +1,184 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe Executor do
6
-
7
- before(:each) do
8
- @orig_stdout = $stdout
9
- $stdout = StringIO.new
10
- end
11
-
12
- after(:each) do
13
- $stdout = @orig_stdout
14
- end
15
-
16
- after(:each) do
17
- @ec.kill unless @ec.nil?
18
- end
19
-
20
- context '#run' do
21
-
22
- it 'raises an exception if no block given' do
23
- lambda {
24
- @ec = Concurrent::Executor.run('Foo')
25
- }.should raise_error
26
- end
27
-
28
- it 'uses the default execution interval when no interval is given' do
29
- @ec = Executor.run('Foo'){ nil }
30
- @ec.execution_interval.should eq Executor::EXECUTION_INTERVAL
31
- end
32
-
33
- it 'uses the default timeout interval when no interval is given' do
34
- @ec = Executor.run('Foo'){ nil }
35
- @ec.timeout_interval.should eq Executor::TIMEOUT_INTERVAL
36
- end
37
-
38
- it 'uses the given execution interval' do
39
- @ec = Executor.run('Foo', execution_interval: 5){ nil }
40
- @ec.execution_interval.should eq 5
41
- end
42
-
43
- it 'uses the given timeout interval' do
44
- @ec = Executor.run('Foo', timeout_interval: 5){ nil }
45
- @ec.timeout_interval.should eq 5
46
- end
47
-
48
- it 'creates a new thread' do
49
- thread = Thread.new{ sleep(1) }
50
- Thread.should_receive(:new).with(any_args()).and_return(thread)
51
- @ec = Executor.run('Foo'){ nil }
52
- end
53
-
54
- it 'returns an ExecutionContext' do
55
- @ec = Executor.run('Foo'){ nil }
56
- @ec.should be_a(Executor::ExecutionContext)
57
- end
58
-
59
- it 'sets the #name context variable' do
60
- @ec = Executor.run('Foo'){ nil }
61
- @ec.name.should eq 'Foo'
62
- end
63
- end
64
-
65
- context 'execution' do
66
-
67
- it 'waits for #execution_interval seconds before executing the block' do
68
- @expected = false
69
- @ec = Executor.run('Foo', execution: 0.5){ @expected = true }
70
- @expected.should be_false
71
- sleep(1)
72
- @expected.should be_true
73
- end
74
-
75
- it 'yields to the execution block' do
76
- @expected = false
77
- @ec = Executor.run('Foo', execution: 1){ @expected = true }
78
- sleep(2)
79
- @expected.should be_true
80
- end
81
-
82
- it 'passes any given arguments to the execution block' do
83
- args = [1,2,3,4]
84
- @expected = nil
85
- @ec = Executor.run('Foo', execution_interval: 0.5, args: args) do |*args|
86
- @expected = args
87
- end
88
- sleep(1)
89
- @expected.should eq args
90
- end
91
-
92
- it 'supresses exceptions thrown by the execution block' do
93
- lambda {
94
- @ec = Executor.run('Foo', execution_interval: 0.5) { raise StandardError }
95
- sleep(1)
96
- }.should_not raise_error
97
- end
98
-
99
- it 'kills the worker thread if the timeout is reached' do
100
- # the after(:each) block will trigger this expectation
101
- Thread.should_receive(:kill).at_least(1).with(any_args())
102
- @ec = Executor.run('Foo', execution_interval: 0.5, timeout_interval: 0.5){ Thread.stop }
103
- sleep(1.5)
104
- end
105
- end
106
-
107
- context 'logging' do
108
-
109
- before(:each) do
110
- @name = nil
111
- @level = nil
112
- @msg = nil
113
-
114
- @logger = proc do |name, level, msg|
115
- @name = name
116
- @level = level
117
- @msg = msg
118
- end
119
- end
120
-
121
- it 'uses a custom logger when given' do
122
- @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
123
- sleep(0.5)
124
- @name.should eq 'Foo'
125
- end
126
-
127
- it 'logs :info when execution is successful' do
128
- @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
129
- sleep(0.5)
130
- @level.should eq :info
131
- end
132
-
133
- it 'logs :warn when execution times out' do
134
- @ec = Executor.run('Foo', execution_interval: 0.1, timeout_interval: 0.1, logger: @logger){ Thread.stop }
135
- sleep(0.5)
136
- @level.should eq :warn
137
- end
138
-
139
- it 'logs :error when execution is fails' do
140
- @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ raise StandardError }
141
- sleep(0.5)
142
- @level.should eq :error
143
- end
144
- end
145
-
146
- context '#status' do
147
-
148
- it 'returns the status of the executor thread when running' do
149
- @ec = Executor.run('Foo'){ nil }
150
- sleep(0.1)
151
- @ec.status.should eq 'sleep'
152
- end
153
-
154
- it 'returns nil when not running' do
155
- @ec = Executor.run('Foo'){ nil }
156
- @ec.kill
157
- sleep(0.1)
158
- @ec.status.should be_nil
159
- end
160
- end
161
-
162
- context '#join' do
163
-
164
- it 'joins the executor thread when running' do
165
- @ec = Executor.run('Foo'){ nil }
166
- Thread.new{ sleep(1); @ec.kill }
167
- @ec.join.should be_a(Thread)
168
- end
169
-
170
- it 'joins the executor thread with timeout when running' do
171
- @ec = Executor.run('Foo'){ nil }
172
- @ec.join(1).should be_nil
173
- end
174
-
175
- it 'immediately returns nil when not running' do
176
- @ec = Executor.run('Foo'){ nil }
177
- @ec.kill
178
- sleep(0.1)
179
- @ec.join.should be_nil
180
- @ec.join(1).should be_nil
181
- end
182
- end
183
- end
184
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe Executor do
6
+
7
+ before(:each) do
8
+ @orig_stdout = $stdout
9
+ $stdout = StringIO.new
10
+ end
11
+
12
+ after(:each) do
13
+ $stdout = @orig_stdout
14
+ end
15
+
16
+ after(:each) do
17
+ @ec.kill unless @ec.nil?
18
+ end
19
+
20
+ context '#run' do
21
+
22
+ it 'raises an exception if no block given' do
23
+ lambda {
24
+ @ec = Concurrent::Executor.run('Foo')
25
+ }.should raise_error
26
+ end
27
+
28
+ it 'uses the default execution interval when no interval is given' do
29
+ @ec = Executor.run('Foo'){ nil }
30
+ @ec.execution_interval.should eq Executor::EXECUTION_INTERVAL
31
+ end
32
+
33
+ it 'uses the default timeout interval when no interval is given' do
34
+ @ec = Executor.run('Foo'){ nil }
35
+ @ec.timeout_interval.should eq Executor::TIMEOUT_INTERVAL
36
+ end
37
+
38
+ it 'uses the given execution interval' do
39
+ @ec = Executor.run('Foo', execution_interval: 5){ nil }
40
+ @ec.execution_interval.should eq 5
41
+ end
42
+
43
+ it 'uses the given timeout interval' do
44
+ @ec = Executor.run('Foo', timeout_interval: 5){ nil }
45
+ @ec.timeout_interval.should eq 5
46
+ end
47
+
48
+ it 'creates a new thread' do
49
+ thread = Thread.new{ sleep(1) }
50
+ Thread.should_receive(:new).with(any_args()).and_return(thread)
51
+ @ec = Executor.run('Foo'){ nil }
52
+ end
53
+
54
+ it 'returns an ExecutionContext' do
55
+ @ec = Executor.run('Foo'){ nil }
56
+ @ec.should be_a(Executor::ExecutionContext)
57
+ end
58
+
59
+ it 'sets the #name context variable' do
60
+ @ec = Executor.run('Foo'){ nil }
61
+ @ec.name.should eq 'Foo'
62
+ end
63
+ end
64
+
65
+ context 'execution' do
66
+
67
+ it 'waits for #execution_interval seconds before executing the block' do
68
+ @expected = false
69
+ @ec = Executor.run('Foo', execution: 0.5){ @expected = true }
70
+ @expected.should be_false
71
+ sleep(1)
72
+ @expected.should be_true
73
+ end
74
+
75
+ it 'yields to the execution block' do
76
+ @expected = false
77
+ @ec = Executor.run('Foo', execution: 1){ @expected = true }
78
+ sleep(2)
79
+ @expected.should be_true
80
+ end
81
+
82
+ it 'passes any given arguments to the execution block' do
83
+ args = [1,2,3,4]
84
+ @expected = nil
85
+ @ec = Executor.run('Foo', execution_interval: 0.5, args: args) do |*args|
86
+ @expected = args
87
+ end
88
+ sleep(1)
89
+ @expected.should eq args
90
+ end
91
+
92
+ it 'supresses exceptions thrown by the execution block' do
93
+ lambda {
94
+ @ec = Executor.run('Foo', execution_interval: 0.5) { raise StandardError }
95
+ sleep(1)
96
+ }.should_not raise_error
97
+ end
98
+
99
+ it 'kills the worker thread if the timeout is reached' do
100
+ # the after(:each) block will trigger this expectation
101
+ Thread.should_receive(:kill).at_least(1).with(any_args())
102
+ @ec = Executor.run('Foo', execution_interval: 0.5, timeout_interval: 0.5){ Thread.stop }
103
+ sleep(1.5)
104
+ end
105
+ end
106
+
107
+ context 'logging' do
108
+
109
+ before(:each) do
110
+ @name = nil
111
+ @level = nil
112
+ @msg = nil
113
+
114
+ @logger = proc do |name, level, msg|
115
+ @name = name
116
+ @level = level
117
+ @msg = msg
118
+ end
119
+ end
120
+
121
+ it 'uses a custom logger when given' do
122
+ @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
123
+ sleep(0.5)
124
+ @name.should eq 'Foo'
125
+ end
126
+
127
+ it 'logs :info when execution is successful' do
128
+ @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
129
+ sleep(0.5)
130
+ @level.should eq :info
131
+ end
132
+
133
+ it 'logs :warn when execution times out' do
134
+ @ec = Executor.run('Foo', execution_interval: 0.1, timeout_interval: 0.1, logger: @logger){ Thread.stop }
135
+ sleep(0.5)
136
+ @level.should eq :warn
137
+ end
138
+
139
+ it 'logs :error when execution is fails' do
140
+ @ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ raise StandardError }
141
+ sleep(0.5)
142
+ @level.should eq :error
143
+ end
144
+ end
145
+
146
+ context '#status' do
147
+
148
+ it 'returns the status of the executor thread when running' do
149
+ @ec = Executor.run('Foo'){ nil }
150
+ sleep(0.1)
151
+ @ec.status.should eq 'sleep'
152
+ end
153
+
154
+ it 'returns nil when not running' do
155
+ @ec = Executor.run('Foo'){ nil }
156
+ @ec.kill
157
+ sleep(0.1)
158
+ @ec.status.should be_nil
159
+ end
160
+ end
161
+
162
+ context '#join' do
163
+
164
+ it 'joins the executor thread when running' do
165
+ @ec = Executor.run('Foo'){ nil }
166
+ Thread.new{ sleep(1); @ec.kill }
167
+ @ec.join.should be_a(Thread)
168
+ end
169
+
170
+ it 'joins the executor thread with timeout when running' do
171
+ @ec = Executor.run('Foo'){ nil }
172
+ @ec.join(1).should be_nil
173
+ end
174
+
175
+ it 'immediately returns nil when not running' do
176
+ @ec = Executor.run('Foo'){ nil }
177
+ @ec.kill
178
+ sleep(0.1)
179
+ @ec.join.should be_nil
180
+ @ec.join(1).should be_nil
181
+ end
182
+ end
183
+ end
184
+ end