concurrent-ruby 0.3.0.pre.1 → 0.3.0.pre.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 +4 -4
- data/README.md +10 -33
- data/lib/concurrent.rb +5 -11
- data/lib/concurrent/{channel.rb → actor.rb} +14 -18
- data/lib/concurrent/agent.rb +5 -4
- data/lib/concurrent/cached_thread_pool.rb +116 -25
- data/lib/concurrent/cached_thread_pool/worker.rb +91 -0
- data/lib/concurrent/event.rb +13 -14
- data/lib/concurrent/event_machine_defer_proxy.rb +0 -1
- data/lib/concurrent/executor.rb +0 -1
- data/lib/concurrent/fixed_thread_pool.rb +111 -14
- data/lib/concurrent/fixed_thread_pool/worker.rb +54 -0
- data/lib/concurrent/future.rb +0 -2
- data/lib/concurrent/global_thread_pool.rb +21 -3
- data/lib/concurrent/goroutine.rb +1 -5
- data/lib/concurrent/obligation.rb +0 -19
- data/lib/concurrent/promise.rb +2 -5
- data/lib/concurrent/runnable.rb +2 -8
- data/lib/concurrent/supervisor.rb +9 -4
- data/lib/concurrent/utilities.rb +24 -0
- data/lib/concurrent/version.rb +1 -1
- data/md/agent.md +3 -3
- data/md/future.md +4 -4
- data/md/promise.md +15 -25
- data/md/thread_pool.md +9 -8
- data/spec/concurrent/actor_spec.rb +377 -0
- data/spec/concurrent/agent_spec.rb +2 -1
- data/spec/concurrent/cached_thread_pool_spec.rb +19 -29
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +1 -1
- data/spec/concurrent/event_spec.rb +1 -1
- data/spec/concurrent/executor_spec.rb +0 -8
- data/spec/concurrent/fixed_thread_pool_spec.rb +27 -16
- data/spec/concurrent/future_spec.rb +0 -13
- data/spec/concurrent/global_thread_pool_spec.rb +73 -0
- data/spec/concurrent/goroutine_spec.rb +0 -15
- data/spec/concurrent/obligation_shared.rb +1 -38
- data/spec/concurrent/promise_spec.rb +28 -47
- data/spec/concurrent/supervisor_spec.rb +1 -2
- data/spec/concurrent/thread_pool_shared.rb +28 -7
- data/spec/concurrent/utilities_spec.rb +50 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support/functions.rb +17 -0
- metadata +12 -27
- data/lib/concurrent/functions.rb +0 -105
- data/lib/concurrent/null_thread_pool.rb +0 -25
- data/lib/concurrent/thread_pool.rb +0 -149
- data/md/reactor.md +0 -32
- data/spec/concurrent/channel_spec.rb +0 -446
- data/spec/concurrent/functions_spec.rb +0 -197
- data/spec/concurrent/null_thread_pool_spec.rb +0 -78
@@ -8,7 +8,6 @@ module Concurrent
|
|
8
8
|
|
9
9
|
let(:worker_class) do
|
10
10
|
Class.new {
|
11
|
-
behavior(:runnable)
|
12
11
|
attr_reader :start_count, :stop_count
|
13
12
|
def run() @start_count ||= 0; @start_count += 1; return true; end
|
14
13
|
def stop() @stop_count ||= 0; @stop_count += 1; return true; end
|
@@ -296,7 +295,7 @@ module Concurrent
|
|
296
295
|
@thread = Thread.new{ sleep(0.5); supervisor.stop }
|
297
296
|
sleep(0.1)
|
298
297
|
lambda {
|
299
|
-
|
298
|
+
Concurrent::timeout(1){ supervisor.run }
|
300
299
|
}.should_not raise_error
|
301
300
|
Thread.kill(@thread) unless @thread.nil?
|
302
301
|
end
|
@@ -43,7 +43,8 @@ share_examples_for :thread_pool do
|
|
43
43
|
|
44
44
|
it 'allows in-progress tasks to complete' do
|
45
45
|
@expected = false
|
46
|
-
subject.post{
|
46
|
+
subject.post{ @expected = true }
|
47
|
+
sleep(0.1)
|
47
48
|
subject.shutdown
|
48
49
|
sleep(1)
|
49
50
|
@expected.should be_true
|
@@ -53,15 +54,20 @@ share_examples_for :thread_pool do
|
|
53
54
|
@expected = false
|
54
55
|
subject.post{ sleep(0.2) }
|
55
56
|
subject.post{ sleep(0.2); @expected = true }
|
57
|
+
sleep(0.1)
|
56
58
|
subject.shutdown
|
57
59
|
sleep(1)
|
58
60
|
@expected.should be_true
|
59
61
|
end
|
60
62
|
|
61
63
|
it 'allows threads to exit normally' do
|
64
|
+
before_thread_count = Thread.list.size
|
65
|
+
10.times{ subject << proc{ nil } }
|
66
|
+
sleep(0.1)
|
67
|
+
Thread.list.size.should > before_thread_count
|
62
68
|
subject.shutdown
|
63
69
|
sleep(1)
|
64
|
-
|
70
|
+
Thread.list.size.should == before_thread_count
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
@@ -69,6 +75,7 @@ share_examples_for :thread_pool do
|
|
69
75
|
|
70
76
|
it 'stops accepting new tasks' do
|
71
77
|
subject.post{ sleep(1) }
|
78
|
+
sleep(0.1)
|
72
79
|
subject.kill
|
73
80
|
@expected = false
|
74
81
|
subject.post{ @expected = true }.should be_false
|
@@ -79,6 +86,7 @@ share_examples_for :thread_pool do
|
|
79
86
|
it 'attempts to kill all in-progress tasks' do
|
80
87
|
@expected = false
|
81
88
|
subject.post{ sleep(1); @expected = true }
|
89
|
+
sleep(0.1)
|
82
90
|
subject.kill
|
83
91
|
sleep(1)
|
84
92
|
@expected.should be_false
|
@@ -88,43 +96,56 @@ share_examples_for :thread_pool do
|
|
88
96
|
@expected = false
|
89
97
|
subject.post{ sleep(0.5) }
|
90
98
|
subject.post{ sleep(0.5); @expected = true }
|
99
|
+
sleep(0.1)
|
91
100
|
subject.kill
|
92
101
|
sleep(1)
|
93
102
|
@expected.should be_false
|
94
103
|
end
|
95
104
|
|
96
105
|
it 'kills all threads' do
|
106
|
+
before_thread_count = Thread.list.size
|
97
107
|
100.times { subject << proc{ sleep(1) } }
|
98
108
|
sleep(0.1)
|
99
|
-
Thread.
|
109
|
+
Thread.list.size.should > before_thread_count
|
100
110
|
subject.kill
|
101
111
|
sleep(0.1)
|
112
|
+
Thread.list.size.should == before_thread_count
|
102
113
|
end
|
103
114
|
end
|
104
115
|
|
105
116
|
context '#wait_for_termination' do
|
106
117
|
|
107
|
-
it 'immediately returns true
|
118
|
+
it 'immediately returns true when no threads running' do
|
119
|
+
subject.shutdown
|
120
|
+
subject.wait_for_termination.should be_true
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'returns true after shutdown has complete' do
|
124
|
+
10.times { subject << proc{ sleep(0.1) } }
|
125
|
+
sleep(0.1)
|
108
126
|
subject.shutdown
|
109
127
|
subject.wait_for_termination.should be_true
|
110
128
|
end
|
111
129
|
|
112
|
-
it 'blocks indefinitely when timeout
|
130
|
+
it 'blocks indefinitely when timeout is nil' do
|
113
131
|
subject.post{ sleep(1) }
|
132
|
+
sleep(0.1)
|
114
133
|
subject.shutdown
|
115
134
|
subject.wait_for_termination(nil).should be_true
|
116
135
|
end
|
117
136
|
|
118
137
|
it 'returns true when shutdown sucessfully completes before timeout' do
|
119
138
|
subject.post{ sleep(0.5) }
|
139
|
+
sleep(0.1)
|
120
140
|
subject.shutdown
|
121
141
|
subject.wait_for_termination(1).should be_true
|
122
142
|
end
|
123
143
|
|
124
144
|
it 'returns false when shutdown fails to complete before timeout' do
|
125
|
-
subject.post{ sleep
|
145
|
+
subject.post{ sleep }
|
146
|
+
sleep(0.1)
|
126
147
|
subject.shutdown
|
127
|
-
subject.wait_for_termination(
|
148
|
+
subject.wait_for_termination(1).should be_false
|
128
149
|
end
|
129
150
|
end
|
130
151
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
describe '#timeout' do
|
6
|
+
|
7
|
+
it 'raises an exception if no block is given' do
|
8
|
+
expect {
|
9
|
+
Concurrent::timeout(1)
|
10
|
+
}.to raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns the value of the block on success' do
|
14
|
+
result = Concurrent::timeout(1) { 42 }
|
15
|
+
result.should eq 42
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'raises an exception if the timeout value is reached' do
|
19
|
+
expect {
|
20
|
+
Concurrent::timeout(1){ sleep }
|
21
|
+
}.to raise_error(Concurrent::TimeoutError)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'bubbles thread exceptions' do
|
25
|
+
expect {
|
26
|
+
Concurrent::timeout(1){ raise NotImplementedError }
|
27
|
+
}.to raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'kills the thread on success' do
|
31
|
+
result = Concurrent::timeout(1) { 42 }
|
32
|
+
Thread.should_receive(:kill).with(any_args())
|
33
|
+
Concurrent::timeout(1){ 42 }
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'kills the thread on timeout' do
|
37
|
+
Thread.should_receive(:kill).with(any_args())
|
38
|
+
expect {
|
39
|
+
Concurrent::timeout(1){ sleep }
|
40
|
+
}.to raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'kills the thread on exception' do
|
44
|
+
Thread.should_receive(:kill).with(any_args())
|
45
|
+
expect {
|
46
|
+
Concurrent::timeout(1){ raise NotImplementedError }
|
47
|
+
}.to raise_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
def delta(v1, v2)
|
4
|
+
if block_given?
|
5
|
+
v1 = yield(v1)
|
6
|
+
v2 = yield(v2)
|
7
|
+
end
|
8
|
+
return (v1 - v2).abs
|
9
|
+
end
|
10
|
+
|
11
|
+
def mri?
|
12
|
+
RbConfig::CONFIG['ruby_install_name']=~ /^ruby$/i
|
13
|
+
end
|
14
|
+
|
15
|
+
def jruby?
|
16
|
+
RbConfig::CONFIG['ruby_install_name']=~ /^jruby$/i
|
17
|
+
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0.pre.
|
4
|
+
version: 0.3.0.pre.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: functional-ruby
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ~>
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.7.4
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ~>
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 0.7.4
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,23 +36,23 @@ extra_rdoc_files:
|
|
50
36
|
files:
|
51
37
|
- README.md
|
52
38
|
- LICENSE
|
39
|
+
- lib/concurrent/actor.rb
|
53
40
|
- lib/concurrent/agent.rb
|
41
|
+
- lib/concurrent/cached_thread_pool/worker.rb
|
54
42
|
- lib/concurrent/cached_thread_pool.rb
|
55
|
-
- lib/concurrent/channel.rb
|
56
43
|
- lib/concurrent/event.rb
|
57
44
|
- lib/concurrent/event_machine_defer_proxy.rb
|
58
45
|
- lib/concurrent/executor.rb
|
46
|
+
- lib/concurrent/fixed_thread_pool/worker.rb
|
59
47
|
- lib/concurrent/fixed_thread_pool.rb
|
60
|
-
- lib/concurrent/functions.rb
|
61
48
|
- lib/concurrent/future.rb
|
62
49
|
- lib/concurrent/global_thread_pool.rb
|
63
50
|
- lib/concurrent/goroutine.rb
|
64
|
-
- lib/concurrent/null_thread_pool.rb
|
65
51
|
- lib/concurrent/obligation.rb
|
66
52
|
- lib/concurrent/promise.rb
|
67
53
|
- lib/concurrent/runnable.rb
|
68
54
|
- lib/concurrent/supervisor.rb
|
69
|
-
- lib/concurrent/
|
55
|
+
- lib/concurrent/utilities.rb
|
70
56
|
- lib/concurrent/version.rb
|
71
57
|
- lib/concurrent.rb
|
72
58
|
- lib/concurrent_ruby.rb
|
@@ -77,21 +63,18 @@ files:
|
|
77
63
|
- md/goroutine.md
|
78
64
|
- md/obligation.md
|
79
65
|
- md/promise.md
|
80
|
-
- md/reactor.md
|
81
66
|
- md/supervisor.md
|
82
67
|
- md/thread_pool.md
|
68
|
+
- spec/concurrent/actor_spec.rb
|
83
69
|
- spec/concurrent/agent_spec.rb
|
84
70
|
- spec/concurrent/cached_thread_pool_spec.rb
|
85
|
-
- spec/concurrent/channel_spec.rb
|
86
71
|
- spec/concurrent/event_machine_defer_proxy_spec.rb
|
87
72
|
- spec/concurrent/event_spec.rb
|
88
73
|
- spec/concurrent/executor_spec.rb
|
89
74
|
- spec/concurrent/fixed_thread_pool_spec.rb
|
90
|
-
- spec/concurrent/functions_spec.rb
|
91
75
|
- spec/concurrent/future_spec.rb
|
92
76
|
- spec/concurrent/global_thread_pool_spec.rb
|
93
77
|
- spec/concurrent/goroutine_spec.rb
|
94
|
-
- spec/concurrent/null_thread_pool_spec.rb
|
95
78
|
- spec/concurrent/obligation_shared.rb
|
96
79
|
- spec/concurrent/promise_spec.rb
|
97
80
|
- spec/concurrent/runnable_shared.rb
|
@@ -99,7 +82,9 @@ files:
|
|
99
82
|
- spec/concurrent/supervisor_spec.rb
|
100
83
|
- spec/concurrent/thread_pool_shared.rb
|
101
84
|
- spec/concurrent/uses_global_thread_pool_shared.rb
|
85
|
+
- spec/concurrent/utilities_spec.rb
|
102
86
|
- spec/spec_helper.rb
|
87
|
+
- spec/support/functions.rb
|
103
88
|
homepage: http://www.concurrent-ruby.com
|
104
89
|
licenses:
|
105
90
|
- MIT
|
@@ -129,18 +114,16 @@ specification_version: 4
|
|
129
114
|
summary: Modern concurrency tools including agents, futures, promises, thread pools,
|
130
115
|
actors, and more.
|
131
116
|
test_files:
|
117
|
+
- spec/concurrent/actor_spec.rb
|
132
118
|
- spec/concurrent/agent_spec.rb
|
133
119
|
- spec/concurrent/cached_thread_pool_spec.rb
|
134
|
-
- spec/concurrent/channel_spec.rb
|
135
120
|
- spec/concurrent/event_machine_defer_proxy_spec.rb
|
136
121
|
- spec/concurrent/event_spec.rb
|
137
122
|
- spec/concurrent/executor_spec.rb
|
138
123
|
- spec/concurrent/fixed_thread_pool_spec.rb
|
139
|
-
- spec/concurrent/functions_spec.rb
|
140
124
|
- spec/concurrent/future_spec.rb
|
141
125
|
- spec/concurrent/global_thread_pool_spec.rb
|
142
126
|
- spec/concurrent/goroutine_spec.rb
|
143
|
-
- spec/concurrent/null_thread_pool_spec.rb
|
144
127
|
- spec/concurrent/obligation_shared.rb
|
145
128
|
- spec/concurrent/promise_spec.rb
|
146
129
|
- spec/concurrent/runnable_shared.rb
|
@@ -148,4 +131,6 @@ test_files:
|
|
148
131
|
- spec/concurrent/supervisor_spec.rb
|
149
132
|
- spec/concurrent/thread_pool_shared.rb
|
150
133
|
- spec/concurrent/uses_global_thread_pool_shared.rb
|
134
|
+
- spec/concurrent/utilities_spec.rb
|
151
135
|
- spec/spec_helper.rb
|
136
|
+
- spec/support/functions.rb
|
data/lib/concurrent/functions.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
require 'concurrent/agent'
|
2
|
-
require 'concurrent/future'
|
3
|
-
require 'concurrent/promise'
|
4
|
-
|
5
|
-
module Kernel
|
6
|
-
|
7
|
-
## agent
|
8
|
-
|
9
|
-
def agent(*args, &block)
|
10
|
-
return Concurrent::Agent.new(*args, &block)
|
11
|
-
end
|
12
|
-
module_function :agent
|
13
|
-
|
14
|
-
def post(object, *args, &block)
|
15
|
-
if object.respond_to?(:post)
|
16
|
-
return object.post(*args, &block)
|
17
|
-
else
|
18
|
-
raise ArgumentError.new('object does not support #post')
|
19
|
-
end
|
20
|
-
end
|
21
|
-
module_function :post
|
22
|
-
|
23
|
-
## future
|
24
|
-
|
25
|
-
def future(*args, &block)
|
26
|
-
return Concurrent::Future.new(*args, &block)
|
27
|
-
end
|
28
|
-
module_function :future
|
29
|
-
|
30
|
-
## obligation
|
31
|
-
|
32
|
-
def deref(object, *args, &block)
|
33
|
-
if object.respond_to?(:deref)
|
34
|
-
return object.deref(*args, &block)
|
35
|
-
elsif object.respond_to?(:value)
|
36
|
-
return object.value(*args, &block)
|
37
|
-
else
|
38
|
-
raise ArgumentError.new('object does not support #deref')
|
39
|
-
end
|
40
|
-
end
|
41
|
-
module_function :deref
|
42
|
-
|
43
|
-
def pending?(object)
|
44
|
-
if object.respond_to?(:pending?)
|
45
|
-
return object.pending?
|
46
|
-
else
|
47
|
-
raise ArgumentError.new('object does not support #pending?')
|
48
|
-
end
|
49
|
-
end
|
50
|
-
module_function :pending?
|
51
|
-
|
52
|
-
def fulfilled?(object)
|
53
|
-
if object.respond_to?(:fulfilled?)
|
54
|
-
return object.fulfilled?
|
55
|
-
elsif object.respond_to?(:realized?)
|
56
|
-
return object.realized?
|
57
|
-
else
|
58
|
-
raise ArgumentError.new('object does not support #fulfilled?')
|
59
|
-
end
|
60
|
-
end
|
61
|
-
module_function :fulfilled?
|
62
|
-
|
63
|
-
def realized?(object)
|
64
|
-
if object.respond_to?(:realized?)
|
65
|
-
return object.realized?
|
66
|
-
elsif object.respond_to?(:fulfilled?)
|
67
|
-
return object.fulfilled?
|
68
|
-
else
|
69
|
-
raise ArgumentError.new('object does not support #realized?')
|
70
|
-
end
|
71
|
-
end
|
72
|
-
module_function :realized?
|
73
|
-
|
74
|
-
def rejected?(object)
|
75
|
-
if object.respond_to?(:rejected?)
|
76
|
-
return object.rejected?
|
77
|
-
else
|
78
|
-
raise ArgumentError.new('object does not support #rejected?')
|
79
|
-
end
|
80
|
-
end
|
81
|
-
module_function :rejected?
|
82
|
-
|
83
|
-
## promise
|
84
|
-
|
85
|
-
# Creates a new promise object. "A promise represents the eventual
|
86
|
-
# value returned from the single completion of an operation."
|
87
|
-
# Promises can be chained in a tree structure where each promise
|
88
|
-
# has zero or more children. Promises are resolved asynchronously
|
89
|
-
# in the order they are added to the tree. Parents are guaranteed
|
90
|
-
# to be resolved before their children. The result of each promise
|
91
|
-
# is passes to each of its children when the child resolves. When
|
92
|
-
# a promise is rejected all its children will be summarily rejected.
|
93
|
-
# A promise added to a rejected promise will immediately be rejected.
|
94
|
-
# A promise that is neither resolved or rejected is pending.
|
95
|
-
#
|
96
|
-
# @param args [Array] zero or more arguments for the block
|
97
|
-
# @param block [Proc] the block to call when attempting fulfillment
|
98
|
-
#
|
99
|
-
# @see Promise
|
100
|
-
# @see http://wiki.commonjs.org/wiki/Promises/A
|
101
|
-
def promise(*args, &block)
|
102
|
-
return Concurrent::Promise.new(*args, &block)
|
103
|
-
end
|
104
|
-
module_function :promise
|
105
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'concurrent/global_thread_pool'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
class NullThreadPool
|
6
|
-
behavior(:global_thread_pool)
|
7
|
-
|
8
|
-
def self.post(*args)
|
9
|
-
Thread.new(*args) do
|
10
|
-
Thread.current.abort_on_exception = false
|
11
|
-
yield(*args)
|
12
|
-
end
|
13
|
-
return true
|
14
|
-
end
|
15
|
-
|
16
|
-
def post(*args, &block)
|
17
|
-
return NullThreadPool.post(*args, &block)
|
18
|
-
end
|
19
|
-
|
20
|
-
def <<(block)
|
21
|
-
NullThreadPool.post(&block)
|
22
|
-
return self
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|