concurrent-ruby 0.1.1.pre.2 → 0.1.1.pre.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|