concurrent-ruby 0.1.1.pre.2 → 0.1.1.pre.3
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.
- data/lib/concurrent.rb +4 -3
- data/lib/concurrent/agent.rb +3 -1
- data/lib/concurrent/defer.rb +4 -4
- data/lib/concurrent/executor.rb +4 -0
- data/lib/concurrent/functions.rb +30 -30
- data/lib/concurrent/future.rb +3 -8
- data/lib/concurrent/global_thread_pool.rb +13 -0
- data/lib/concurrent/null_thread_pool.rb +22 -0
- data/lib/concurrent/promise.rb +4 -10
- data/lib/concurrent/reactor/drb_async_demux.rb +74 -0
- data/lib/concurrent/reactor/tcp_sync_demux.rb +98 -0
- data/lib/concurrent/thread_pool.rb +7 -3
- data/lib/concurrent/version.rb +1 -1
- data/md/defer.md +4 -4
- data/md/promise.md +2 -0
- data/md/thread_pool.md +27 -0
- data/spec/concurrent/agent_spec.rb +5 -1
- data/spec/concurrent/cached_thread_pool_spec.rb +13 -0
- data/spec/concurrent/defer_spec.rb +9 -23
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +13 -10
- data/spec/concurrent/executor_spec.rb +38 -0
- data/spec/concurrent/functions_spec.rb +160 -0
- data/spec/concurrent/future_spec.rb +2 -19
- data/spec/concurrent/global_thread_pool_spec.rb +38 -0
- data/spec/concurrent/null_thread_pool_spec.rb +54 -0
- data/spec/concurrent/promise_spec.rb +6 -0
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +12 -0
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +12 -0
- data/spec/concurrent/reactor_spec.rb +10 -0
- data/spec/concurrent/thread_pool_shared.rb +3 -2
- data/spec/spec_helper.rb +9 -0
- metadata +15 -4
- data/lib/concurrent/drb_async_demux.rb +0 -72
- data/lib/concurrent/tcp_sync_demux.rb +0 -96
@@ -21,7 +21,7 @@ module Concurrent
|
|
21
21
|
end
|
22
22
|
|
23
23
|
before(:each) do
|
24
|
-
|
24
|
+
Future.thread_pool = FixedThreadPool.new(1)
|
25
25
|
end
|
26
26
|
|
27
27
|
it_should_behave_like Obligation
|
@@ -40,17 +40,10 @@ module Concurrent
|
|
40
40
|
context '#initialize' do
|
41
41
|
|
42
42
|
it 'spawns a new thread when a block is given' do
|
43
|
-
|
43
|
+
Future.thread_pool.should_receive(:post).once.with(any_args())
|
44
44
|
Future.new{ nil }
|
45
45
|
end
|
46
46
|
|
47
|
-
it 'accepts an alternate thread pool as the first argument' do
|
48
|
-
pool = Concurrent::FixedThreadPool.new(2)
|
49
|
-
pool.should_receive(:post).with(no_args())
|
50
|
-
Future.new(pool, 1, 2, 3){ nil }
|
51
|
-
sleep(0.1)
|
52
|
-
end
|
53
|
-
|
54
47
|
it 'does not spawns a new thread when no block given' do
|
55
48
|
Thread.should_not_receive(:new).with(any_args())
|
56
49
|
Future.new
|
@@ -76,16 +69,6 @@ module Concurrent
|
|
76
69
|
[@a, @b, @c].should eq [1, 2, 3]
|
77
70
|
end
|
78
71
|
|
79
|
-
it 'passes all other arguments to the handler when a thread pool is given' do
|
80
|
-
@expected = nil
|
81
|
-
pool = Concurrent::FixedThreadPool.new(2)
|
82
|
-
f = Future.new(pool, 1, 2, 3) do |a, b, c|
|
83
|
-
@a, @b, @c = a, b, c
|
84
|
-
end
|
85
|
-
sleep(0.1)
|
86
|
-
[@a, @b, @c].should eq [1, 2, 3]
|
87
|
-
end
|
88
|
-
|
89
72
|
it 'sets the value to the result of the handler' do
|
90
73
|
f = Future.new(10){|a| a * 2 }
|
91
74
|
sleep(0.1)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
describe UsesGlobalThreadPool do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
$GLOBAL_THREAD_POOL = FixedThreadPool.new(1)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'defaults to the global thread pool' do
|
12
|
+
clazz = Class.new{ include UsesGlobalThreadPool }
|
13
|
+
clazz.thread_pool.should eq $GLOBAL_THREAD_POOL
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'sets and gets the thread pool for the class' do
|
17
|
+
pool = NullThreadPool.new
|
18
|
+
clazz = Class.new{ include UsesGlobalThreadPool }
|
19
|
+
|
20
|
+
clazz.thread_pool = pool
|
21
|
+
clazz.thread_pool.should eq pool
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'gives each class its own thread pool' do
|
25
|
+
clazz1 = Class.new{ include UsesGlobalThreadPool }
|
26
|
+
clazz2 = Class.new{ include UsesGlobalThreadPool }
|
27
|
+
clazz3 = Class.new{ include UsesGlobalThreadPool }
|
28
|
+
|
29
|
+
clazz1.thread_pool = FixedThreadPool.new(1)
|
30
|
+
clazz2.thread_pool = CachedThreadPool.new
|
31
|
+
clazz3.thread_pool = NullThreadPool.new
|
32
|
+
|
33
|
+
clazz1.thread_pool.should_not eq clazz2.thread_pool
|
34
|
+
clazz2.thread_pool.should_not eq clazz3.thread_pool
|
35
|
+
clazz3.thread_pool.should_not eq clazz1.thread_pool
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'concurrent/goroutine'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
describe NullThreadPool do
|
8
|
+
|
9
|
+
subject { NullThreadPool.new }
|
10
|
+
|
11
|
+
after(:all) do
|
12
|
+
$GLOBAL_THREAD_POOL = FixedThreadPool.new(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
context '#post' do
|
16
|
+
|
17
|
+
it 'proxies a call without arguments' do
|
18
|
+
Thread.should_receive(:new).with(no_args())
|
19
|
+
$GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
|
20
|
+
subject.post{ nil }
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'proxies a call with arguments' do
|
24
|
+
Thread.should_receive(:new).with(1,2,3)
|
25
|
+
$GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
|
26
|
+
subject.post(1,2,3){ nil }
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'aliases #<<' do
|
30
|
+
Thread.should_receive(:new).with(no_args())
|
31
|
+
$GLOBAL_THREAD_POOL.should_not_receive(:post).with(any_args())
|
32
|
+
subject << proc{ nil }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'operation' do
|
37
|
+
|
38
|
+
context 'goroutine' do
|
39
|
+
|
40
|
+
it 'gets a new thread' do
|
41
|
+
$GLOBAL_THREAD_POOL = subject
|
42
|
+
|
43
|
+
t = Thread.new{ nil }
|
44
|
+
|
45
|
+
Thread.should_receive(:new).with(no_args()).and_return(t)
|
46
|
+
go{ nil }
|
47
|
+
|
48
|
+
Thread.should_receive(:new).with(1,2,3).and_return(t)
|
49
|
+
go(1,2,3){ nil }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -21,6 +21,10 @@ module Concurrent
|
|
21
21
|
rescue{ nil }.tap(){ sleep(0.1) }
|
22
22
|
end
|
23
23
|
|
24
|
+
before(:each) do
|
25
|
+
Promise.thread_pool = FixedThreadPool.new(1)
|
26
|
+
end
|
27
|
+
|
24
28
|
it_should_behave_like Obligation
|
25
29
|
|
26
30
|
context 'behavior' do
|
@@ -194,6 +198,8 @@ module Concurrent
|
|
194
198
|
end
|
195
199
|
|
196
200
|
it 'searches associated rescue handlers in order' do
|
201
|
+
Promise.thread_pool = CachedThreadPool.new
|
202
|
+
|
197
203
|
@expected = nil
|
198
204
|
Promise.new{ raise ArgumentError }.
|
199
205
|
rescue(ArgumentError){|ex| @expected = 1 }.
|
@@ -29,8 +29,9 @@ module Concurrent
|
|
29
29
|
|
30
30
|
context '#shutdown?' do
|
31
31
|
|
32
|
-
it 'returns true if #shutdown
|
32
|
+
it 'returns true if #shutdown is complete' do
|
33
33
|
subject.shutdown
|
34
|
+
sleep(0.1)
|
34
35
|
subject.should be_shutdown
|
35
36
|
end
|
36
37
|
|
@@ -139,7 +140,7 @@ module Concurrent
|
|
139
140
|
it 'returns false when shutdown fails to complete before timeout' do
|
140
141
|
subject.post{ sleep(1) }
|
141
142
|
subject.shutdown
|
142
|
-
subject.wait_for_termination(0.5).should
|
143
|
+
subject.wait_for_termination(0.5).should be_false
|
143
144
|
end
|
144
145
|
end
|
145
146
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.1.pre.
|
4
|
+
version: 0.1.1.pre.3
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: functional-ruby
|
@@ -59,7 +59,6 @@ files:
|
|
59
59
|
- lib/concurrent/agent.rb
|
60
60
|
- lib/concurrent/cached_thread_pool.rb
|
61
61
|
- lib/concurrent/defer.rb
|
62
|
-
- lib/concurrent/drb_async_demux.rb
|
63
62
|
- lib/concurrent/event.rb
|
64
63
|
- lib/concurrent/event_machine_defer_proxy.rb
|
65
64
|
- lib/concurrent/executor.rb
|
@@ -68,11 +67,13 @@ files:
|
|
68
67
|
- lib/concurrent/future.rb
|
69
68
|
- lib/concurrent/global_thread_pool.rb
|
70
69
|
- lib/concurrent/goroutine.rb
|
70
|
+
- lib/concurrent/null_thread_pool.rb
|
71
71
|
- lib/concurrent/obligation.rb
|
72
72
|
- lib/concurrent/promise.rb
|
73
|
+
- lib/concurrent/reactor/drb_async_demux.rb
|
74
|
+
- lib/concurrent/reactor/tcp_sync_demux.rb
|
73
75
|
- lib/concurrent/reactor.rb
|
74
76
|
- lib/concurrent/smart_mutex.rb
|
75
|
-
- lib/concurrent/tcp_sync_demux.rb
|
76
77
|
- lib/concurrent/thread_pool.rb
|
77
78
|
- lib/concurrent/utilities.rb
|
78
79
|
- lib/concurrent/version.rb
|
@@ -96,9 +97,14 @@ files:
|
|
96
97
|
- spec/concurrent/fixed_thread_pool_spec.rb
|
97
98
|
- spec/concurrent/functions_spec.rb
|
98
99
|
- spec/concurrent/future_spec.rb
|
100
|
+
- spec/concurrent/global_thread_pool_spec.rb
|
99
101
|
- spec/concurrent/goroutine_spec.rb
|
102
|
+
- spec/concurrent/null_thread_pool_spec.rb
|
100
103
|
- spec/concurrent/obligation_shared.rb
|
101
104
|
- spec/concurrent/promise_spec.rb
|
105
|
+
- spec/concurrent/reactor/drb_async_demux_spec.rb
|
106
|
+
- spec/concurrent/reactor/tcp_sync_demux_spec.rb
|
107
|
+
- spec/concurrent/reactor_spec.rb
|
102
108
|
- spec/concurrent/smart_mutex_spec.rb
|
103
109
|
- spec/concurrent/thread_pool_shared.rb
|
104
110
|
- spec/concurrent/utilities_spec.rb
|
@@ -138,9 +144,14 @@ test_files:
|
|
138
144
|
- spec/concurrent/fixed_thread_pool_spec.rb
|
139
145
|
- spec/concurrent/functions_spec.rb
|
140
146
|
- spec/concurrent/future_spec.rb
|
147
|
+
- spec/concurrent/global_thread_pool_spec.rb
|
141
148
|
- spec/concurrent/goroutine_spec.rb
|
149
|
+
- spec/concurrent/null_thread_pool_spec.rb
|
142
150
|
- spec/concurrent/obligation_shared.rb
|
143
151
|
- spec/concurrent/promise_spec.rb
|
152
|
+
- spec/concurrent/reactor/drb_async_demux_spec.rb
|
153
|
+
- spec/concurrent/reactor/tcp_sync_demux_spec.rb
|
154
|
+
- spec/concurrent/reactor_spec.rb
|
144
155
|
- spec/concurrent/smart_mutex_spec.rb
|
145
156
|
- spec/concurrent/thread_pool_shared.rb
|
146
157
|
- spec/concurrent/utilities_spec.rb
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'drb/drb'
|
2
|
-
require 'drb/acl'
|
3
|
-
require 'functional'
|
4
|
-
require 'concurrent/reactor'
|
5
|
-
|
6
|
-
module Concurrent
|
7
|
-
|
8
|
-
class DRbAsyncDemux
|
9
|
-
|
10
|
-
behavior(:async_event_demux)
|
11
|
-
|
12
|
-
DEFAULT_URI = 'druby://localhost:12345'
|
13
|
-
DEFAULT_ACL = %[allow all]
|
14
|
-
|
15
|
-
def initialize(opts = {})
|
16
|
-
@uri = opts[:uri] || DEFAULT_URI
|
17
|
-
@acl = ACL.new(opts[:acl] || DEFAULT_ACL)
|
18
|
-
end
|
19
|
-
|
20
|
-
def set_reactor(reactor)
|
21
|
-
raise ArgumentError.new('invalid reactor') unless reactor.behaves_as?(:demux_reactor)
|
22
|
-
@reactor = reactor
|
23
|
-
end
|
24
|
-
|
25
|
-
def start
|
26
|
-
DRb.install_acl(@acl)
|
27
|
-
@service = DRb.start_service(@uri, Demultiplexer.new(@reactor))
|
28
|
-
end
|
29
|
-
|
30
|
-
def stop
|
31
|
-
@service = DRb.stop_service
|
32
|
-
end
|
33
|
-
|
34
|
-
def stopped?
|
35
|
-
return @service.nil?
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
class Demultiplexer
|
41
|
-
|
42
|
-
def initialize(reactor)
|
43
|
-
@reactor = reactor
|
44
|
-
end
|
45
|
-
|
46
|
-
Concurrent::Reactor::RESERVED_EVENTS.each do |event|
|
47
|
-
define_method(event){|*args| false }
|
48
|
-
end
|
49
|
-
|
50
|
-
def method_missing(method, *args, &block)
|
51
|
-
(class << self; self; end).class_eval do
|
52
|
-
define_method(method) do |*args|
|
53
|
-
result = @reactor.handle(method, *args)
|
54
|
-
case result.first
|
55
|
-
when :ok
|
56
|
-
return result.last
|
57
|
-
when :ex
|
58
|
-
raise result.last
|
59
|
-
when :noop
|
60
|
-
raise NoMethodError.new("undefined method '#{method}' for #{self}")
|
61
|
-
else
|
62
|
-
raise DRb::DRbUnknownError.new("unexpected error when calling method '#{method}'")
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
self.send(method, *args)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
DRbAsyncDemultiplexer = DRbAsyncDemux
|
72
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require 'drb/acl'
|
3
|
-
require 'functional'
|
4
|
-
require 'concurrent/reactor'
|
5
|
-
|
6
|
-
module Concurrent
|
7
|
-
|
8
|
-
class TcpSyncDemux
|
9
|
-
|
10
|
-
behavior(:sync_event_demux)
|
11
|
-
|
12
|
-
DEFAULT_HOST = '127.0.0.1'
|
13
|
-
DEFAULT_PORT = 12345
|
14
|
-
DEFAULT_ACL = %[allow all]
|
15
|
-
|
16
|
-
def initialize(opts = {})
|
17
|
-
@host = opts[:host] || DEFAULT_HOST
|
18
|
-
@port = opts[:port] || DEFAULT_PORT
|
19
|
-
@acl = ACL.new(opts[:acl] || DEFAULT_ACL)
|
20
|
-
end
|
21
|
-
|
22
|
-
def start
|
23
|
-
@server = TCPServer.new(@host, @port)
|
24
|
-
end
|
25
|
-
|
26
|
-
def stop
|
27
|
-
atomic {
|
28
|
-
@socket.close unless @socket.nil?
|
29
|
-
@server.close unless @server.nil?
|
30
|
-
@server = @socket = nil
|
31
|
-
}
|
32
|
-
end
|
33
|
-
|
34
|
-
def stopped?
|
35
|
-
return @server.nil?
|
36
|
-
end
|
37
|
-
|
38
|
-
def accept
|
39
|
-
@socket = @server.accept if @socket.nil?
|
40
|
-
return nil unless @acl.allow_socket?(@socket)
|
41
|
-
event, args = get_message(@socket)
|
42
|
-
return nil if event.nil?
|
43
|
-
return Reactor::EventContext.new(event, args)
|
44
|
-
end
|
45
|
-
|
46
|
-
def respond(result, message)
|
47
|
-
return nil if @socket.nil?
|
48
|
-
@socket.puts(format_message(result, message))
|
49
|
-
end
|
50
|
-
|
51
|
-
def close
|
52
|
-
@socket.close
|
53
|
-
@socket = nil
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.format_message(event, *args)
|
57
|
-
args = args.reduce('') do |memo, arg|
|
58
|
-
memo << "#{arg}\r\n"
|
59
|
-
end
|
60
|
-
return ":#{event}\r\n#{args}\r\n"
|
61
|
-
end
|
62
|
-
def format_message(*args) self.class.format_message(*args); end
|
63
|
-
|
64
|
-
def self.parse_message(message)
|
65
|
-
return atomic {
|
66
|
-
event = message.first.match /^:?(\w+)/
|
67
|
-
event = event[1].to_s.downcase.to_sym unless event.nil?
|
68
|
-
|
69
|
-
args = message.slice(1, message.length) || []
|
70
|
-
|
71
|
-
[event, args]
|
72
|
-
}
|
73
|
-
end
|
74
|
-
def parse_message(*args) self.class.parse_message(*args); end
|
75
|
-
|
76
|
-
def self.get_message(socket)
|
77
|
-
message = []
|
78
|
-
while line = socket.gets
|
79
|
-
if line.nil? || (line = line.strip).empty?
|
80
|
-
break
|
81
|
-
else
|
82
|
-
message << line
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
if message.empty?
|
87
|
-
return nil
|
88
|
-
else
|
89
|
-
return parse_message(message)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
def get_message(*args) self.class.get_message(*args); end
|
93
|
-
end
|
94
|
-
|
95
|
-
TcpSyncDemultiplexer = TcpSyncDemux
|
96
|
-
end
|