concurrent-ruby 0.2.2 → 0.3.0.pre.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.
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