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

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 (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