concurrent-ruby 0.2.2 → 0.3.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +45 -42
  3. data/lib/concurrent.rb +5 -6
  4. data/lib/concurrent/agent.rb +29 -33
  5. data/lib/concurrent/cached_thread_pool.rb +26 -105
  6. data/lib/concurrent/channel.rb +94 -0
  7. data/lib/concurrent/event.rb +8 -17
  8. data/lib/concurrent/executor.rb +68 -72
  9. data/lib/concurrent/fixed_thread_pool.rb +15 -83
  10. data/lib/concurrent/functions.rb +7 -22
  11. data/lib/concurrent/future.rb +29 -9
  12. data/lib/concurrent/null_thread_pool.rb +5 -2
  13. data/lib/concurrent/obligation.rb +6 -16
  14. data/lib/concurrent/promise.rb +9 -10
  15. data/lib/concurrent/runnable.rb +103 -0
  16. data/lib/concurrent/supervisor.rb +271 -44
  17. data/lib/concurrent/thread_pool.rb +112 -39
  18. data/lib/concurrent/version.rb +1 -1
  19. data/md/executor.md +9 -3
  20. data/md/goroutine.md +11 -9
  21. data/md/reactor.md +32 -0
  22. data/md/supervisor.md +43 -0
  23. data/spec/concurrent/agent_spec.rb +128 -51
  24. data/spec/concurrent/cached_thread_pool_spec.rb +33 -47
  25. data/spec/concurrent/channel_spec.rb +446 -0
  26. data/spec/concurrent/event_machine_defer_proxy_spec.rb +3 -1
  27. data/spec/concurrent/event_spec.rb +0 -19
  28. data/spec/concurrent/executor_spec.rb +167 -119
  29. data/spec/concurrent/fixed_thread_pool_spec.rb +40 -30
  30. data/spec/concurrent/functions_spec.rb +0 -20
  31. data/spec/concurrent/future_spec.rb +88 -0
  32. data/spec/concurrent/null_thread_pool_spec.rb +23 -2
  33. data/spec/concurrent/obligation_shared.rb +0 -5
  34. data/spec/concurrent/promise_spec.rb +9 -10
  35. data/spec/concurrent/runnable_shared.rb +62 -0
  36. data/spec/concurrent/runnable_spec.rb +233 -0
  37. data/spec/concurrent/supervisor_spec.rb +912 -47
  38. data/spec/concurrent/thread_pool_shared.rb +18 -31
  39. data/spec/spec_helper.rb +10 -3
  40. metadata +17 -23
  41. data/lib/concurrent/defer.rb +0 -65
  42. data/lib/concurrent/reactor.rb +0 -166
  43. data/lib/concurrent/reactor/drb_async_demux.rb +0 -83
  44. data/lib/concurrent/reactor/tcp_sync_demux.rb +0 -131
  45. data/lib/concurrent/utilities.rb +0 -32
  46. data/md/defer.md +0 -174
  47. data/spec/concurrent/defer_spec.rb +0 -199
  48. data/spec/concurrent/reactor/drb_async_demux_spec.rb +0 -196
  49. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +0 -410
  50. data/spec/concurrent/reactor_spec.rb +0 -364
  51. data/spec/concurrent/utilities_spec.rb +0 -74
@@ -1,6 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
- share_examples_for 'Thread Pool' do
3
+ share_examples_for :thread_pool do
4
+
5
+ after(:each) do
6
+ subject.kill
7
+ sleep(0.1)
8
+ end
4
9
 
5
10
  context '#running?' do
6
11
 
@@ -25,32 +30,6 @@ share_examples_for 'Thread Pool' do
25
30
  end
26
31
  end
27
32
 
28
- context '#shutdown?' do
29
-
30
- it 'returns true if #shutdown is complete' do
31
- subject.shutdown
32
- sleep(0.1)
33
- subject.should be_shutdown
34
- end
35
-
36
- it 'returns false when running' do
37
- subject.should_not be_shutdown
38
- end
39
- end
40
-
41
- context '#killed?' do
42
-
43
- it 'returns true if tasks were killed at shutdown' do
44
- subject.post{ sleep(1) }
45
- subject.kill
46
- subject.should be_killed
47
- end
48
-
49
- it 'returns false when running' do
50
- subject.should_not be_killed
51
- end
52
- end
53
-
54
33
  context '#shutdown' do
55
34
 
56
35
  it 'stops accepting new tasks' do
@@ -113,6 +92,14 @@ share_examples_for 'Thread Pool' do
113
92
  sleep(1)
114
93
  @expected.should be_false
115
94
  end
95
+
96
+ it 'kills all threads' do
97
+ 100.times { subject << proc{ sleep(1) } }
98
+ sleep(0.1)
99
+ Thread.should_receive(:kill).at_least(subject.size).times
100
+ subject.kill
101
+ sleep(0.1)
102
+ end
116
103
  end
117
104
 
118
105
  context '#wait_for_termination' do
@@ -150,12 +137,12 @@ share_examples_for 'Thread Pool' do
150
137
  end
151
138
 
152
139
  it 'returns true when the block is added to the queue' do
153
- subject.post{ nil }.should be_true
140
+ subject.post{ sleep }.should be_true
154
141
  end
155
142
 
156
143
  it 'calls the block with the given arguments' do
157
144
  @expected = nil
158
- subject.post(1, 2, 3)do |a, b, c|
145
+ subject.post(1, 2, 3) do |a, b, c|
159
146
  @expected = a + b + c
160
147
  end
161
148
  sleep(0.1)
@@ -166,7 +153,7 @@ share_examples_for 'Thread Pool' do
166
153
  subject.post{ sleep(1) }
167
154
  subject.shutdown
168
155
  @expected = nil
169
- subject.post(1, 2, 3)do |a, b, c|
156
+ subject.post(1, 2, 3) do |a, b, c|
170
157
  @expected = a + b + c
171
158
  end
172
159
  @expected.should be_nil
@@ -181,7 +168,7 @@ share_examples_for 'Thread Pool' do
181
168
  it 'rejects the block once shutdown' do
182
169
  subject.shutdown
183
170
  @expected = nil
184
- subject.post(1, 2, 3)do |a, b, c|
171
+ subject.post(1, 2, 3) do |a, b, c|
185
172
  @expected = a + b + c
186
173
  end
187
174
  @expected.should be_nil
@@ -1,4 +1,11 @@
1
1
  require 'simplecov'
2
+ require 'coveralls'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+
2
9
  SimpleCov.start do
3
10
  project_name 'concurrent-ruby'
4
11
  add_filter '/md/'
@@ -12,8 +19,6 @@ require 'eventmachine'
12
19
  require 'concurrent'
13
20
  require 'concurrent/functions'
14
21
 
15
- require 'functional'
16
-
17
22
  # import all the support files
18
23
  Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require File.expand_path(f) }
19
24
 
@@ -27,6 +32,8 @@ RSpec.configure do |config|
27
32
  end
28
33
 
29
34
  config.after(:each) do
35
+ Thread.list.each do |thread|
36
+ thread.kill unless thread == Thread.current
37
+ end
30
38
  end
31
-
32
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jerry D'Antonio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-20 00:00:00.000000000 Z
11
+ date: 2013-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: functional-ruby
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  description: |2
42
- Modern concurrency tools including agents, futures, promises, thread pools, reactors, supervisors, and more.
42
+ Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
43
43
  Inspired by Erlang, Clojure, Go, JavaScript, actors, and classic concurrency patterns.
44
44
  email: jerry.dantonio@gmail.com
45
45
  executables: []
@@ -52,7 +52,7 @@ files:
52
52
  - LICENSE
53
53
  - lib/concurrent/agent.rb
54
54
  - lib/concurrent/cached_thread_pool.rb
55
- - lib/concurrent/defer.rb
55
+ - lib/concurrent/channel.rb
56
56
  - lib/concurrent/event.rb
57
57
  - lib/concurrent/event_machine_defer_proxy.rb
58
58
  - lib/concurrent/executor.rb
@@ -64,27 +64,25 @@ files:
64
64
  - lib/concurrent/null_thread_pool.rb
65
65
  - lib/concurrent/obligation.rb
66
66
  - lib/concurrent/promise.rb
67
- - lib/concurrent/reactor/drb_async_demux.rb
68
- - lib/concurrent/reactor/tcp_sync_demux.rb
69
- - lib/concurrent/reactor.rb
67
+ - lib/concurrent/runnable.rb
70
68
  - lib/concurrent/supervisor.rb
71
69
  - lib/concurrent/thread_pool.rb
72
- - lib/concurrent/utilities.rb
73
70
  - lib/concurrent/version.rb
74
71
  - lib/concurrent.rb
75
72
  - lib/concurrent_ruby.rb
76
73
  - md/agent.md
77
- - md/defer.md
78
74
  - md/event.md
79
75
  - md/executor.md
80
76
  - md/future.md
81
77
  - md/goroutine.md
82
78
  - md/obligation.md
83
79
  - md/promise.md
80
+ - md/reactor.md
81
+ - md/supervisor.md
84
82
  - md/thread_pool.md
85
83
  - spec/concurrent/agent_spec.rb
86
84
  - spec/concurrent/cached_thread_pool_spec.rb
87
- - spec/concurrent/defer_spec.rb
85
+ - spec/concurrent/channel_spec.rb
88
86
  - spec/concurrent/event_machine_defer_proxy_spec.rb
89
87
  - spec/concurrent/event_spec.rb
90
88
  - spec/concurrent/executor_spec.rb
@@ -96,13 +94,11 @@ files:
96
94
  - spec/concurrent/null_thread_pool_spec.rb
97
95
  - spec/concurrent/obligation_shared.rb
98
96
  - spec/concurrent/promise_spec.rb
99
- - spec/concurrent/reactor/drb_async_demux_spec.rb
100
- - spec/concurrent/reactor/tcp_sync_demux_spec.rb
101
- - spec/concurrent/reactor_spec.rb
97
+ - spec/concurrent/runnable_shared.rb
98
+ - spec/concurrent/runnable_spec.rb
102
99
  - spec/concurrent/supervisor_spec.rb
103
100
  - spec/concurrent/thread_pool_shared.rb
104
101
  - spec/concurrent/uses_global_thread_pool_shared.rb
105
- - spec/concurrent/utilities_spec.rb
106
102
  - spec/spec_helper.rb
107
103
  homepage: http://www.concurrent-ruby.com
108
104
  licenses:
@@ -122,20 +118,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
118
  version: 1.9.2
123
119
  required_rubygems_version: !ruby/object:Gem::Requirement
124
120
  requirements:
125
- - - '>='
121
+ - - '>'
126
122
  - !ruby/object:Gem::Version
127
- version: '0'
123
+ version: 1.3.1
128
124
  requirements: []
129
125
  rubyforge_project:
130
- rubygems_version: 2.0.6
126
+ rubygems_version: 2.1.5
131
127
  signing_key:
132
128
  specification_version: 4
133
129
  summary: Modern concurrency tools including agents, futures, promises, thread pools,
134
- reactors, and more.
130
+ actors, and more.
135
131
  test_files:
136
132
  - spec/concurrent/agent_spec.rb
137
133
  - spec/concurrent/cached_thread_pool_spec.rb
138
- - spec/concurrent/defer_spec.rb
134
+ - spec/concurrent/channel_spec.rb
139
135
  - spec/concurrent/event_machine_defer_proxy_spec.rb
140
136
  - spec/concurrent/event_spec.rb
141
137
  - spec/concurrent/executor_spec.rb
@@ -147,11 +143,9 @@ test_files:
147
143
  - spec/concurrent/null_thread_pool_spec.rb
148
144
  - spec/concurrent/obligation_shared.rb
149
145
  - spec/concurrent/promise_spec.rb
150
- - spec/concurrent/reactor/drb_async_demux_spec.rb
151
- - spec/concurrent/reactor/tcp_sync_demux_spec.rb
152
- - spec/concurrent/reactor_spec.rb
146
+ - spec/concurrent/runnable_shared.rb
147
+ - spec/concurrent/runnable_spec.rb
153
148
  - spec/concurrent/supervisor_spec.rb
154
149
  - spec/concurrent/thread_pool_shared.rb
155
150
  - spec/concurrent/uses_global_thread_pool_shared.rb
156
- - spec/concurrent/utilities_spec.rb
157
151
  - spec/spec_helper.rb
@@ -1,65 +0,0 @@
1
- require 'thread'
2
-
3
- require 'concurrent/global_thread_pool'
4
-
5
- module Concurrent
6
-
7
- IllegalMethodCallError = Class.new(StandardError)
8
-
9
- class Defer
10
- include UsesGlobalThreadPool
11
-
12
- def initialize(opts = {}, &block)
13
- operation = opts[:op] || opts[:operation]
14
- @callback = opts[:cback] || opts[:callback]
15
- @errorback = opts[:eback] || opts[:error] || opts[:errorback]
16
- thread_pool = opts[:pool] || opts[:thread_pool]
17
-
18
- raise ArgumentError.new('no operation given') if operation.nil? && ! block_given?
19
- raise ArgumentError.new('two operations given') if ! operation.nil? && block_given?
20
-
21
- @operation = operation || block
22
-
23
- if operation.nil?
24
- @running = false
25
- else
26
- self.go
27
- end
28
- end
29
-
30
- def then(&block)
31
- raise IllegalMethodCallError.new('a callback has already been provided') unless @callback.nil?
32
- raise IllegalMethodCallError.new('the defer is already running') if @running
33
- raise ArgumentError.new('no block given') unless block_given?
34
- @callback = block
35
- return self
36
- end
37
-
38
- def rescue(&block)
39
- raise IllegalMethodCallError.new('a errorback has already been provided') unless @errorback.nil?
40
- raise IllegalMethodCallError.new('the defer is already running') if @running
41
- raise ArgumentError.new('no block given') unless block_given?
42
- @errorback = block
43
- return self
44
- end
45
- alias_method :catch, :rescue
46
- alias_method :on_error, :rescue
47
-
48
- def go
49
- return nil if @running
50
- @running = true
51
- Defer.thread_pool.post { fulfill }
52
- return nil
53
- end
54
-
55
- private
56
-
57
- # @private
58
- def fulfill # :nodoc:
59
- result = @operation.call
60
- @callback.call(result) unless @callback.nil?
61
- rescue Exception => ex
62
- @errorback.call(ex) unless @errorback.nil?
63
- end
64
- end
65
- end
@@ -1,166 +0,0 @@
1
- require 'thread'
2
- require 'functional'
3
- require 'concurrent/supervisor'
4
-
5
- behavior_info(:sync_event_demux,
6
- run: 0,
7
- stop: 0,
8
- running?: 0,
9
- accept: 0,
10
- respond: 2)
11
-
12
- behavior_info(:async_event_demux,
13
- run: 0,
14
- stop: 0,
15
- running?: 0,
16
- set_reactor: 1)
17
-
18
- behavior_info(:demux_reactor,
19
- handle: -2)
20
-
21
- module Concurrent
22
-
23
- class Reactor
24
-
25
- behavior(:demux_reactor)
26
- behavior(:runnable)
27
-
28
- RESERVED_EVENTS = [ :stop ]
29
-
30
- EventContext = Struct.new(:event, :args, :callback)
31
-
32
- def initialize(demux = nil)
33
- @demux = demux
34
- if @demux.nil? || @demux.behaves_as?(:async_event_demux)
35
- @sync = false
36
- @queue = Queue.new
37
- @demux.set_reactor(self) unless @demux.nil?
38
- elsif @demux.behaves_as?(:sync_event_demux)
39
- @sync = true
40
- else
41
- raise ArgumentError.new("invalid event demultiplexer '#{@demux}'")
42
- end
43
-
44
- @running = false
45
- @handlers = Hash.new
46
- @mutex = Mutex.new
47
- end
48
-
49
- def running?
50
- return @running
51
- end
52
-
53
- def add_handler(event, &block)
54
- raise ArgumentError.new('no block given') unless block_given?
55
- event = event.to_sym
56
- raise ArgumentError.new("'#{event}' is a reserved event") if RESERVED_EVENTS.include?(event)
57
- @mutex.synchronize {
58
- @handlers[event] = block
59
- }
60
- return true
61
- end
62
-
63
- def remove_handler(event)
64
- handler = @mutex.synchronize {
65
- @handlers.delete(event.to_sym)
66
- }
67
- return ! handler.nil?
68
- end
69
-
70
- def stop_on_signal(*signals)
71
- signals.each{|signal| Signal.trap(signal){ Thread.new{ self.stop }.abort_on_exception = false}}
72
- end
73
-
74
- def handle(event, *args)
75
- raise NotImplementedError.new("demultiplexer '#{@demux.class}' is synchronous") if @sync
76
- return [:stopped, 'reactor not running'] unless running?
77
- context = EventContext.new(event.to_sym, args.dup, Queue.new)
78
- @queue.push(context)
79
- return context.callback.pop
80
- end
81
-
82
- def run
83
- raise StandardError.new('already running') if self.running?
84
- @sync ? (@running = true; run_sync) : (@running = true; run_async)
85
- end
86
- alias_method :run, :run
87
-
88
- def stop
89
- return true unless self.running?
90
- if @sync
91
- @demux.stop
92
- else
93
- @queue.push(:stop)
94
- end
95
- return true
96
- end
97
-
98
- private
99
-
100
- def handle_event(context)
101
- raise ArgumentError.new('no block given') unless block_given?
102
-
103
- handler = @mutex.synchronize {
104
- @handlers[context.event]
105
- }
106
-
107
- if handler.nil?
108
- response = yield(:noop, "'#{context.event}' handler not found")
109
- else
110
- begin
111
- result = handler.call(*context.args)
112
- response = yield(:ok, result)
113
- rescue Exception => ex
114
- response = yield(:ex, ex)
115
- end
116
- end
117
-
118
- return response
119
- end
120
-
121
- def finalize_stop
122
- @mutex.synchronize do
123
- @running = false
124
- @demux.stop unless @demux.nil?
125
- @demux = nil
126
- end
127
- end
128
-
129
- def run_sync
130
- @demux.run
131
-
132
- loop do
133
- break unless @demux.running?
134
- context = @demux.accept
135
- begin
136
- if context.nil?
137
- @demux.stop
138
- else
139
- response = handle_event(context) do |result, message|
140
- [result, message]
141
- end
142
- @demux.respond(*response)
143
- end
144
- rescue Exception => ex
145
- @demux.respond(:abend, ex)
146
- end
147
- end
148
-
149
- finalize_stop
150
- end
151
-
152
- def run_async
153
- @demux.run unless @demux.nil?
154
-
155
- loop do
156
- context = @queue.pop
157
- break if context == :stop
158
- handle_event(context) do |result, message|
159
- context.callback.push([result, message])
160
- end
161
- end
162
-
163
- finalize_stop
164
- end
165
- end
166
- end