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,162 +1,161 @@
1
- require 'thread'
2
- require 'functional'
3
- require 'concurrent/smart_mutex'
4
-
5
- behavior_info(:sync_event_demux,
6
- start: 0,
7
- stop: 0,
8
- stopped?: 0,
9
- accept: 0,
10
- respond: 2,
11
- close: 0)
12
-
13
- behavior_info(:async_event_demux,
14
- start: 0,
15
- stop: 0,
16
- stopped?: 0,
17
- set_reactor: 1)
18
-
19
- behavior_info(:demux_reactor,
20
- handle: -2)
21
-
22
- module Concurrent
23
-
24
- class Reactor
25
-
26
- behavior(:demux_reactor)
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 = SmartMutex.new
47
- end
48
-
49
- def add_handler(event, &block)
50
- event = event.to_sym
51
- raise ArgumentError.new("'#{event}' is a reserved event") if RESERVED_EVENTS.include?(event)
52
- raise ArgumentError.new('no block given') unless block_given?
53
- @mutex.synchronize {
54
- @handlers[event] = block
55
- }
56
- return true
57
- end
58
-
59
- def remove_handler(event)
60
- handler = @mutex.synchronize {
61
- @handlers.delete(event.to_sym)
62
- }
63
- return ! handler.nil?
64
- end
65
-
66
- def stop_on_signal(*signals)
67
- signals.each{|signal| Signal.trap(signal){ Thread.new{ self.stop }}}
68
- end
69
-
70
- def handle_event(event, *args)
71
- raise NotImplementedError.new("demultiplexer '#{@demux.class}' is synchronous") if @sync
72
- return [:stopped, 'reactor not running'] unless running?
73
- context = EventContext.new(event.to_sym, args.dup, Queue.new)
74
- @queue.push(context)
75
- return context.callback.pop
76
- end
77
- alias_method :handle, :handle_event
78
-
79
- def running?
80
- return @running
81
- end
82
-
83
- def start
84
- raise StandardError.new('already running') if self.running?
85
- @sync ? (@running = true; run_sync) : (@running = true; run_async)
86
- end
87
-
88
- def stop
89
- return unless self.running?
90
- if @sync
91
- @demux.stop
92
- else
93
- @queue.push(:stop)
94
- end
95
- return nil
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
- atomic {
123
- @running = false
124
- @demux.stop unless @demux.nil?
125
- @demux = nil
126
- }
127
- end
128
-
129
- def run_sync
130
- @demux.start
131
-
132
- loop do
133
- break if @demux.stopped?
134
- context = @demux.accept
135
- if context.nil?
136
- @demux.close
137
- else
138
- response = handle_event(context) do |result, message|
139
- [result, message]
140
- end
141
- @demux.respond(*response)
142
- end
143
- end
144
-
145
- finalize_stop
146
- end
147
-
148
- def run_async
149
- @demux.start unless @demux.nil?
150
-
151
- loop do
152
- context = @queue.pop
153
- break if context == :stop
154
- handle_event(context) do |result, message|
155
- context.callback.push([result, message])
156
- end
157
- end
158
-
159
- finalize_stop
160
- end
161
- end
162
- end
1
+ require 'thread'
2
+ require 'functional'
3
+
4
+ behavior_info(:sync_event_demux,
5
+ start: 0,
6
+ stop: 0,
7
+ stopped?: 0,
8
+ accept: 0,
9
+ respond: 2,
10
+ close: 0)
11
+
12
+ behavior_info(:async_event_demux,
13
+ start: 0,
14
+ stop: 0,
15
+ stopped?: 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
+
27
+ RESERVED_EVENTS = [ :stop ]
28
+
29
+ EventContext = Struct.new(:event, :args, :callback)
30
+
31
+ def initialize(demux = nil)
32
+ @demux = demux
33
+ if @demux.nil? || @demux.behaves_as?(:async_event_demux)
34
+ @sync = false
35
+ @queue = Queue.new
36
+ @demux.set_reactor(self) unless @demux.nil?
37
+ elsif @demux.behaves_as?(:sync_event_demux)
38
+ @sync = true
39
+ else
40
+ raise ArgumentError.new("invalid event demultiplexer '#{@demux}'")
41
+ end
42
+
43
+ @running = false
44
+ @handlers = Hash.new
45
+ @mutex = Mutex.new
46
+ end
47
+
48
+ def running?
49
+ return @running
50
+ end
51
+
52
+ def add_handler(event, &block)
53
+ raise ArgumentError.new('no block given') unless block_given?
54
+ event = event.to_sym
55
+ raise ArgumentError.new("'#{event}' is a reserved event") if RESERVED_EVENTS.include?(event)
56
+ @mutex.synchronize {
57
+ @handlers[event] = block
58
+ }
59
+ return true
60
+ end
61
+
62
+ def remove_handler(event)
63
+ handler = @mutex.synchronize {
64
+ @handlers.delete(event.to_sym)
65
+ }
66
+ return ! handler.nil?
67
+ end
68
+
69
+ def stop_on_signal(*signals)
70
+ signals.each{|signal| Signal.trap(signal){ Thread.new{ self.stop }}}
71
+ end
72
+
73
+ def handle(event, *args)
74
+ raise NotImplementedError.new("demultiplexer '#{@demux.class}' is synchronous") if @sync
75
+ return [:stopped, 'reactor not running'] unless running?
76
+ context = EventContext.new(event.to_sym, args.dup, Queue.new)
77
+ @queue.push(context)
78
+ return context.callback.pop
79
+ end
80
+
81
+ def start
82
+ raise StandardError.new('already running') if self.running?
83
+ @sync ? (@running = true; run_sync) : (@running = true; run_async)
84
+ end
85
+ alias_method :run, :start
86
+
87
+ def stop
88
+ return true unless self.running?
89
+ if @sync
90
+ @demux.stop
91
+ else
92
+ @queue.push(:stop)
93
+ end
94
+ return true
95
+ end
96
+
97
+ private
98
+
99
+ def handle_event(context)
100
+ raise ArgumentError.new('no block given') unless block_given?
101
+
102
+ handler = @mutex.synchronize {
103
+ @handlers[context.event]
104
+ }
105
+
106
+ if handler.nil?
107
+ response = yield(:noop, "'#{context.event}' handler not found")
108
+ else
109
+ begin
110
+ result = handler.call(*context.args)
111
+ response = yield(:ok, result)
112
+ rescue Exception => ex
113
+ response = yield(:ex, ex)
114
+ end
115
+ end
116
+
117
+ return response
118
+ end
119
+
120
+ def finalize_stop
121
+ @mutex.synchronize do
122
+ @running = false
123
+ @demux.stop unless @demux.nil?
124
+ @demux = nil
125
+ end
126
+ end
127
+
128
+ def run_sync
129
+ @demux.start
130
+
131
+ loop do
132
+ break if @demux.stopped?
133
+ context = @demux.accept
134
+ if context.nil?
135
+ @demux.close
136
+ else
137
+ response = handle_event(context) do |result, message|
138
+ [result, message]
139
+ end
140
+ @demux.respond(*response)
141
+ end
142
+ end
143
+
144
+ finalize_stop
145
+ end
146
+
147
+ def run_async
148
+ @demux.start unless @demux.nil?
149
+
150
+ loop do
151
+ context = @queue.pop
152
+ break if context == :stop
153
+ handle_event(context) do |result, message|
154
+ context.callback.push([result, message])
155
+ end
156
+ end
157
+
158
+ finalize_stop
159
+ end
160
+ end
161
+ end
@@ -1,74 +1,74 @@
1
- require 'drb/drb'
2
- require 'drb/acl'
3
- require 'functional'
4
- require 'concurrent/reactor'
5
-
6
- module Concurrent
7
- class Reactor
8
-
9
- class DRbAsyncDemux
10
-
11
- behavior(:async_event_demux)
12
-
13
- DEFAULT_URI = 'druby://localhost:12345'
14
- DEFAULT_ACL = %[allow all]
15
-
16
- def initialize(opts = {})
17
- @uri = opts[:uri] || DEFAULT_URI
18
- @acl = ACL.new(opts[:acl] || DEFAULT_ACL)
19
- end
20
-
21
- def set_reactor(reactor)
22
- raise ArgumentError.new('invalid reactor') unless reactor.behaves_as?(:demux_reactor)
23
- @reactor = reactor
24
- end
25
-
26
- def start
27
- DRb.install_acl(@acl)
28
- @service = DRb.start_service(@uri, Demultiplexer.new(@reactor))
29
- end
30
-
31
- def stop
32
- @service = DRb.stop_service
33
- end
34
-
35
- def stopped?
36
- return @service.nil?
37
- end
38
-
39
- private
40
-
41
- class Demultiplexer
42
-
43
- def initialize(reactor)
44
- @reactor = reactor
45
- end
46
-
47
- Concurrent::Reactor::RESERVED_EVENTS.each do |event|
48
- define_method(event){|*args| false }
49
- end
50
-
51
- def method_missing(method, *args, &block)
52
- (class << self; self; end).class_eval do
53
- define_method(method) do |*args|
54
- result = @reactor.handle(method, *args)
55
- case result.first
56
- when :ok
57
- return result.last
58
- when :ex
59
- raise result.last
60
- when :noop
61
- raise NoMethodError.new("undefined method '#{method}' for #{self}")
62
- else
63
- raise DRb::DRbUnknownError.new("unexpected error when calling method '#{method}'")
64
- end
65
- end
66
- end
67
- self.send(method, *args)
68
- end
69
- end
70
- end
71
-
72
- DRbAsyncDemultiplexer = DRbAsyncDemux
73
- end
74
- end
1
+ require 'drb/drb'
2
+ require 'drb/acl'
3
+ require 'functional'
4
+ require 'concurrent/reactor'
5
+
6
+ module Concurrent
7
+ class Reactor
8
+
9
+ class DRbAsyncDemux
10
+
11
+ behavior(:async_event_demux)
12
+
13
+ DEFAULT_URI = 'druby://localhost:12345'
14
+ DEFAULT_ACL = %w[allow all]
15
+
16
+ def initialize(opts = {})
17
+ @uri = opts[:uri] || DEFAULT_URI
18
+ @acl = ACL.new(opts[:acl] || DEFAULT_ACL)
19
+ end
20
+
21
+ def set_reactor(reactor)
22
+ raise ArgumentError.new('invalid reactor') unless reactor.behaves_as?(:demux_reactor)
23
+ @reactor = reactor
24
+ end
25
+
26
+ def start
27
+ DRb.install_acl(@acl)
28
+ @service = DRb.start_service(@uri, Demultiplexer.new(@reactor))
29
+ end
30
+
31
+ def stop
32
+ @service = DRb.stop_service
33
+ end
34
+
35
+ def stopped?
36
+ return @service.nil?
37
+ end
38
+
39
+ private
40
+
41
+ class Demultiplexer
42
+
43
+ def initialize(reactor)
44
+ @reactor = reactor
45
+ end
46
+
47
+ Concurrent::Reactor::RESERVED_EVENTS.each do |event|
48
+ define_method(event){|*args| false }
49
+ end
50
+
51
+ def method_missing(method, *args, &block)
52
+ (class << self; self; end).class_eval do
53
+ define_method(method) do |*args|
54
+ result = @reactor.handle(method, *args)
55
+ case result.first
56
+ when :ok
57
+ return result.last
58
+ when :ex
59
+ raise result.last
60
+ when :noop
61
+ raise NoMethodError.new("undefined method '#{method}' for #{self}")
62
+ else
63
+ raise DRb::DRbUnknownError.new("unexpected error when calling method '#{method}'")
64
+ end
65
+ end
66
+ end
67
+ self.send(method, *args)
68
+ end
69
+ end
70
+ end
71
+
72
+ DRbAsyncDemultiplexer = DRbAsyncDemux
73
+ end
74
+ end