concurrent-ruby 0.2.1 → 0.2.2
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.
- checksums.yaml +7 -0
- data/LICENSE +21 -21
- data/README.md +276 -275
- data/lib/concurrent.rb +28 -28
- data/lib/concurrent/agent.rb +114 -114
- data/lib/concurrent/cached_thread_pool.rb +131 -131
- data/lib/concurrent/defer.rb +65 -65
- data/lib/concurrent/event.rb +60 -60
- data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
- data/lib/concurrent/executor.rb +96 -96
- data/lib/concurrent/fixed_thread_pool.rb +99 -99
- data/lib/concurrent/functions.rb +120 -120
- data/lib/concurrent/future.rb +42 -42
- data/lib/concurrent/global_thread_pool.rb +24 -16
- data/lib/concurrent/goroutine.rb +29 -29
- data/lib/concurrent/null_thread_pool.rb +22 -22
- data/lib/concurrent/obligation.rb +67 -67
- data/lib/concurrent/promise.rb +174 -174
- data/lib/concurrent/reactor.rb +166 -166
- data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
- data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
- data/lib/concurrent/supervisor.rb +105 -105
- data/lib/concurrent/thread_pool.rb +76 -76
- data/lib/concurrent/utilities.rb +32 -32
- data/lib/concurrent/version.rb +3 -3
- data/lib/concurrent_ruby.rb +1 -1
- data/md/agent.md +123 -123
- data/md/defer.md +174 -174
- data/md/event.md +32 -32
- data/md/executor.md +187 -187
- data/md/future.md +83 -83
- data/md/goroutine.md +52 -52
- data/md/obligation.md +32 -32
- data/md/promise.md +227 -227
- data/md/thread_pool.md +224 -224
- data/spec/concurrent/agent_spec.rb +390 -386
- data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
- data/spec/concurrent/defer_spec.rb +199 -195
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
- data/spec/concurrent/event_spec.rb +134 -134
- data/spec/concurrent/executor_spec.rb +200 -200
- data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
- data/spec/concurrent/functions_spec.rb +217 -217
- data/spec/concurrent/future_spec.rb +112 -108
- data/spec/concurrent/global_thread_pool_spec.rb +11 -38
- data/spec/concurrent/goroutine_spec.rb +67 -67
- data/spec/concurrent/null_thread_pool_spec.rb +57 -57
- data/spec/concurrent/obligation_shared.rb +132 -132
- data/spec/concurrent/promise_spec.rb +316 -312
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
- data/spec/concurrent/reactor_spec.rb +364 -364
- data/spec/concurrent/supervisor_spec.rb +269 -269
- data/spec/concurrent/thread_pool_shared.rb +204 -204
- data/spec/concurrent/uses_global_thread_pool_shared.rb +64 -0
- data/spec/concurrent/utilities_spec.rb +74 -74
- data/spec/spec_helper.rb +32 -32
- metadata +17 -19
data/lib/concurrent/reactor.rb
CHANGED
@@ -1,166 +1,166 @@
|
|
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
|
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
|
@@ -1,83 +1,83 @@
|
|
1
|
-
require 'drb/drb'
|
2
|
-
require 'drb/acl'
|
3
|
-
require 'functional'
|
4
|
-
require 'concurrent/reactor'
|
5
|
-
require 'concurrent/supervisor'
|
6
|
-
|
7
|
-
module Concurrent
|
8
|
-
class Reactor
|
9
|
-
|
10
|
-
class DRbAsyncDemux
|
11
|
-
|
12
|
-
behavior(:async_event_demux)
|
13
|
-
|
14
|
-
DEFAULT_URI = 'druby://localhost:12345'
|
15
|
-
DEFAULT_ACL = %w{deny all allow 127.0.0.1}
|
16
|
-
|
17
|
-
attr_reader :uri
|
18
|
-
attr_reader :acl
|
19
|
-
|
20
|
-
def initialize(opts = {})
|
21
|
-
@uri = opts[:uri] || DEFAULT_URI
|
22
|
-
@acl = ACL.new(opts[:acl] || DEFAULT_ACL)
|
23
|
-
end
|
24
|
-
|
25
|
-
def set_reactor(reactor)
|
26
|
-
raise ArgumentError.new('invalid reactor') unless reactor.behaves_as?(:demux_reactor)
|
27
|
-
@reactor = reactor
|
28
|
-
end
|
29
|
-
|
30
|
-
def run
|
31
|
-
raise StandardError.new('already running') if running?
|
32
|
-
DRb.install_acl(@acl)
|
33
|
-
@service = DRb.start_service(@uri, Demultiplexer.new(@reactor))
|
34
|
-
end
|
35
|
-
|
36
|
-
def stop
|
37
|
-
@service = DRb.stop_service
|
38
|
-
end
|
39
|
-
|
40
|
-
def running?
|
41
|
-
return ! @service.nil?
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
class Demultiplexer
|
47
|
-
|
48
|
-
def initialize(reactor)
|
49
|
-
@reactor = reactor
|
50
|
-
end
|
51
|
-
|
52
|
-
Concurrent::Reactor::RESERVED_EVENTS.each do |event|
|
53
|
-
define_method(event){|*args| false }
|
54
|
-
end
|
55
|
-
|
56
|
-
def method_missing(method, *args, &block)
|
57
|
-
(class << self; self; end).class_eval do
|
58
|
-
define_method(method) do |*args|
|
59
|
-
begin
|
60
|
-
result = @reactor.handle(method, *args)
|
61
|
-
rescue Exception => ex
|
62
|
-
raise DRb::DRbRemoteError.new(ex)
|
63
|
-
end
|
64
|
-
case result.first
|
65
|
-
when :ok
|
66
|
-
return result.last
|
67
|
-
when :ex
|
68
|
-
raise result.last
|
69
|
-
when :noop
|
70
|
-
raise NoMethodError.new("undefined method '#{method}' for #{self}")
|
71
|
-
else
|
72
|
-
raise DRb::DRbError.new("unexpected response from method '#{method}'")
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
self.send(method, *args)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
DRbAsyncDemultiplexer = DRbAsyncDemux
|
82
|
-
end
|
83
|
-
end
|
1
|
+
require 'drb/drb'
|
2
|
+
require 'drb/acl'
|
3
|
+
require 'functional'
|
4
|
+
require 'concurrent/reactor'
|
5
|
+
require 'concurrent/supervisor'
|
6
|
+
|
7
|
+
module Concurrent
|
8
|
+
class Reactor
|
9
|
+
|
10
|
+
class DRbAsyncDemux
|
11
|
+
|
12
|
+
behavior(:async_event_demux)
|
13
|
+
|
14
|
+
DEFAULT_URI = 'druby://localhost:12345'
|
15
|
+
DEFAULT_ACL = %w{deny all allow 127.0.0.1}
|
16
|
+
|
17
|
+
attr_reader :uri
|
18
|
+
attr_reader :acl
|
19
|
+
|
20
|
+
def initialize(opts = {})
|
21
|
+
@uri = opts[:uri] || DEFAULT_URI
|
22
|
+
@acl = ACL.new(opts[:acl] || DEFAULT_ACL)
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_reactor(reactor)
|
26
|
+
raise ArgumentError.new('invalid reactor') unless reactor.behaves_as?(:demux_reactor)
|
27
|
+
@reactor = reactor
|
28
|
+
end
|
29
|
+
|
30
|
+
def run
|
31
|
+
raise StandardError.new('already running') if running?
|
32
|
+
DRb.install_acl(@acl)
|
33
|
+
@service = DRb.start_service(@uri, Demultiplexer.new(@reactor))
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop
|
37
|
+
@service = DRb.stop_service
|
38
|
+
end
|
39
|
+
|
40
|
+
def running?
|
41
|
+
return ! @service.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
class Demultiplexer
|
47
|
+
|
48
|
+
def initialize(reactor)
|
49
|
+
@reactor = reactor
|
50
|
+
end
|
51
|
+
|
52
|
+
Concurrent::Reactor::RESERVED_EVENTS.each do |event|
|
53
|
+
define_method(event){|*args| false }
|
54
|
+
end
|
55
|
+
|
56
|
+
def method_missing(method, *args, &block)
|
57
|
+
(class << self; self; end).class_eval do
|
58
|
+
define_method(method) do |*args|
|
59
|
+
begin
|
60
|
+
result = @reactor.handle(method, *args)
|
61
|
+
rescue Exception => ex
|
62
|
+
raise DRb::DRbRemoteError.new(ex)
|
63
|
+
end
|
64
|
+
case result.first
|
65
|
+
when :ok
|
66
|
+
return result.last
|
67
|
+
when :ex
|
68
|
+
raise result.last
|
69
|
+
when :noop
|
70
|
+
raise NoMethodError.new("undefined method '#{method}' for #{self}")
|
71
|
+
else
|
72
|
+
raise DRb::DRbError.new("unexpected response from method '#{method}'")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
self.send(method, *args)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
DRbAsyncDemultiplexer = DRbAsyncDemux
|
82
|
+
end
|
83
|
+
end
|