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.
- checksums.yaml +7 -0
- data/LICENSE +21 -21
- data/README.md +275 -279
- data/lib/concurrent.rb +27 -28
- data/lib/concurrent/agent.rb +114 -108
- data/lib/concurrent/cached_thread_pool.rb +129 -130
- data/lib/concurrent/defer.rb +65 -67
- data/lib/concurrent/event.rb +60 -60
- data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
- data/lib/concurrent/executor.rb +93 -95
- data/lib/concurrent/fixed_thread_pool.rb +95 -89
- data/lib/concurrent/functions.rb +120 -120
- data/lib/concurrent/future.rb +42 -47
- data/lib/concurrent/global_thread_pool.rb +16 -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 -166
- data/lib/concurrent/reactor.rb +161 -162
- data/lib/concurrent/reactor/drb_async_demux.rb +74 -74
- data/lib/concurrent/reactor/tcp_sync_demux.rb +98 -98
- data/lib/concurrent/thread_pool.rb +76 -69
- data/lib/concurrent/utilities.rb +32 -34
- 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 +176 -176
- 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 +386 -380
- data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
- data/spec/concurrent/defer_spec.rb +195 -195
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -253
- data/spec/concurrent/event_spec.rb +134 -134
- data/spec/concurrent/executor_spec.rb +184 -184
- data/spec/concurrent/fixed_thread_pool_spec.rb +83 -84
- data/spec/concurrent/functions_spec.rb +217 -217
- data/spec/concurrent/future_spec.rb +108 -108
- data/spec/concurrent/global_thread_pool_spec.rb +38 -38
- data/spec/concurrent/goroutine_spec.rb +67 -67
- data/spec/concurrent/null_thread_pool_spec.rb +54 -54
- data/spec/concurrent/obligation_shared.rb +135 -121
- data/spec/concurrent/promise_spec.rb +312 -305
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +12 -12
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +12 -12
- data/spec/concurrent/reactor_spec.rb +351 -10
- data/spec/concurrent/thread_pool_shared.rb +209 -210
- data/spec/concurrent/utilities_spec.rb +74 -74
- data/spec/spec_helper.rb +44 -30
- metadata +11 -22
- data/lib/concurrent/smart_mutex.rb +0 -66
- data/spec/concurrent/smart_mutex_spec.rb +0 -234
data/lib/concurrent/reactor.rb
CHANGED
@@ -1,162 +1,161 @@
|
|
1
|
-
require 'thread'
|
2
|
-
require 'functional'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@demux
|
34
|
-
|
35
|
-
@
|
36
|
-
@
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@
|
45
|
-
@
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
}
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
@
|
75
|
-
return
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
@
|
124
|
-
@demux
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
context
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
context
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|