concurrent-ruby 0.1.0 → 0.1.1.pre.1

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.
Files changed (51) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +279 -224
  3. data/lib/concurrent.rb +27 -20
  4. data/lib/concurrent/agent.rb +106 -130
  5. data/lib/concurrent/cached_thread_pool.rb +130 -122
  6. data/lib/concurrent/defer.rb +67 -69
  7. data/lib/concurrent/drb_async_demux.rb +72 -0
  8. data/lib/concurrent/event.rb +60 -60
  9. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  10. data/lib/concurrent/executor.rb +87 -0
  11. data/lib/concurrent/fixed_thread_pool.rb +89 -89
  12. data/lib/concurrent/functions.rb +120 -0
  13. data/lib/concurrent/future.rb +52 -42
  14. data/lib/concurrent/global_thread_pool.rb +3 -3
  15. data/lib/concurrent/goroutine.rb +29 -25
  16. data/lib/concurrent/obligation.rb +67 -121
  17. data/lib/concurrent/promise.rb +172 -194
  18. data/lib/concurrent/reactor.rb +162 -0
  19. data/lib/concurrent/smart_mutex.rb +66 -0
  20. data/lib/concurrent/tcp_sync_demux.rb +96 -0
  21. data/lib/concurrent/thread_pool.rb +65 -61
  22. data/lib/concurrent/utilities.rb +34 -0
  23. data/lib/concurrent/version.rb +3 -3
  24. data/lib/concurrent_ruby.rb +1 -1
  25. data/md/agent.md +123 -123
  26. data/md/defer.md +174 -174
  27. data/md/event.md +32 -32
  28. data/md/executor.md +176 -0
  29. data/md/future.md +83 -83
  30. data/md/goroutine.md +52 -52
  31. data/md/obligation.md +32 -32
  32. data/md/promise.md +225 -225
  33. data/md/thread_pool.md +197 -197
  34. data/spec/concurrent/agent_spec.rb +376 -405
  35. data/spec/concurrent/cached_thread_pool_spec.rb +112 -112
  36. data/spec/concurrent/defer_spec.rb +209 -199
  37. data/spec/concurrent/event_machine_defer_proxy_spec.rb +250 -246
  38. data/spec/concurrent/event_spec.rb +134 -134
  39. data/spec/concurrent/executor_spec.rb +146 -0
  40. data/spec/concurrent/fixed_thread_pool_spec.rb +84 -84
  41. data/spec/concurrent/functions_spec.rb +57 -0
  42. data/spec/concurrent/future_spec.rb +125 -115
  43. data/spec/concurrent/goroutine_spec.rb +67 -52
  44. data/spec/concurrent/obligation_shared.rb +121 -121
  45. data/spec/concurrent/promise_spec.rb +299 -310
  46. data/spec/concurrent/smart_mutex_spec.rb +234 -0
  47. data/spec/concurrent/thread_pool_shared.rb +209 -209
  48. data/spec/concurrent/utilities_spec.rb +74 -0
  49. data/spec/spec_helper.rb +21 -19
  50. metadata +38 -14
  51. checksums.yaml +0 -7
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe Agent do
6
+
7
+ it 'aliases #<< for Agent#post' do
8
+ subject = Agent.new(0)
9
+ subject << proc{ 100 }
10
+ sleep(0.1)
11
+ subject.value.should eq 100
12
+ end
13
+
14
+ it 'aliases Kernel#agent for Agent.new' do
15
+ agent(10).should be_a(Agent)
16
+ end
17
+
18
+ it 'aliases Kernel#deref for #deref' do
19
+ deref(Agent.new(10)).should eq 10
20
+ deref(Agent.new(10), 10).should eq 10
21
+ end
22
+
23
+ it 'aliases Kernel:post for Agent#post' do
24
+ subject = Agent.new(0)
25
+ post(subject){ 100 }
26
+ sleep(0.1)
27
+ subject.value.should eq 100
28
+ end
29
+ end
30
+
31
+ describe Defer do
32
+
33
+ it 'aliases Kernel#defer' do
34
+ defer{ nil }.should be_a(Defer)
35
+ end
36
+ end
37
+
38
+ describe Future do
39
+
40
+ it 'aliases Kernel#future for Future.new' do
41
+ future().should be_a(Future)
42
+ future(){ nil }.should be_a(Future)
43
+ future(1, 2, 3).should be_a(Future)
44
+ future(1, 2, 3){ nil }.should be_a(Future)
45
+ end
46
+ end
47
+
48
+ describe Promise do
49
+
50
+ it 'aliases Kernel#promise for Promise.new' do
51
+ promise().should be_a(Promise)
52
+ promise(){ nil }.should be_a(Promise)
53
+ promise(1, 2, 3).should be_a(Promise)
54
+ promise(1, 2, 3){ nil }.should be_a(Promise)
55
+ end
56
+ end
57
+ end
@@ -1,115 +1,125 @@
1
- require 'spec_helper'
2
- require_relative 'obligation_shared'
3
-
4
- module Concurrent
5
-
6
- describe Future do
7
-
8
- let!(:fulfilled_value) { 10 }
9
- let!(:rejected_reason) { StandardError.new('mojo jojo') }
10
-
11
- let(:pending_subject) do
12
- Future.new{ sleep(2) }
13
- end
14
-
15
- let(:fulfilled_subject) do
16
- Future.new{ fulfilled_value }.tap(){ sleep(0.1) }
17
- end
18
-
19
- let(:rejected_subject) do
20
- Future.new{ raise rejected_reason }.tap(){ sleep(0.1) }
21
- end
22
-
23
- before(:each) do
24
- $GLOBAL_THREAD_POOL = CachedThreadPool.new
25
- end
26
-
27
- it_should_behave_like Obligation
28
-
29
- context 'behavior' do
30
-
31
- it 'implements :future behavior' do
32
- lambda {
33
- Future.new{ nil }
34
- }.should_not raise_error
35
-
36
- Future.new{ nil }.behaves_as?(:future).should be_true
37
- end
38
- end
39
-
40
- context '#initialize' do
41
-
42
- it 'spawns a new thread when a block is given' do
43
- $GLOBAL_THREAD_POOL.should_receive(:post).once.with(any_args())
44
- Future.new{ nil }
45
- end
46
-
47
- it 'does not spawns a new thread when no block given' do
48
- Thread.should_not_receive(:new).with(any_args())
49
- Future.new
50
- end
51
-
52
- it 'immediately sets the state to :fulfilled when no block given' do
53
- Future.new.should be_fulfilled
54
- end
55
-
56
- it 'immediately sets the value to nil when no block given' do
57
- Future.new.value.should be_nil
58
- end
59
- end
60
-
61
- context 'fulfillment' do
62
-
63
- it 'passes all arguments to handler' do
64
- @a = @b = @c = nil
65
- f = Future.new(1, 2, 3) do |a, b, c|
66
- @a, @b, @c = a, b, c
67
- end
68
- sleep(0.1)
69
- [@a, @b, @c].should eq [1, 2, 3]
70
- end
71
-
72
- it 'sets the value to the result of the handler' do
73
- f = Future.new(10){|a| a * 2 }
74
- sleep(0.1)
75
- f.value.should eq 20
76
- end
77
-
78
- it 'sets the state to :fulfilled when the block completes' do
79
- f = Future.new(10){|a| a * 2 }
80
- sleep(0.1)
81
- f.should be_fulfilled
82
- end
83
-
84
- it 'sets the value to nil when the handler raises an exception' do
85
- f = Future.new{ raise StandardError }
86
- sleep(0.1)
87
- f.value.should be_nil
88
- end
89
-
90
- it 'sets the state to :rejected when the handler raises an exception' do
91
- f = Future.new{ raise StandardError }
92
- sleep(0.1)
93
- f.should be_rejected
94
- end
95
-
96
- context 'aliases' do
97
-
98
- it 'aliases #realized? for #fulfilled?' do
99
- fulfilled_subject.should be_realized
100
- end
101
-
102
- it 'aliases #deref for #value' do
103
- fulfilled_subject.deref.should eq fulfilled_value
104
- end
105
-
106
- it 'aliases Kernel#future for Future.new' do
107
- future().should be_a(Future)
108
- future(){ nil }.should be_a(Future)
109
- future(1, 2, 3).should be_a(Future)
110
- future(1, 2, 3){ nil }.should be_a(Future)
111
- end
112
- end
113
- end
114
- end
115
- end
1
+ require 'spec_helper'
2
+ require_relative 'obligation_shared'
3
+
4
+ module Concurrent
5
+
6
+ describe Future do
7
+
8
+ let!(:fulfilled_value) { 10 }
9
+ let!(:rejected_reason) { StandardError.new('mojo jojo') }
10
+
11
+ let(:pending_subject) do
12
+ Future.new{ sleep(2) }
13
+ end
14
+
15
+ let(:fulfilled_subject) do
16
+ Future.new{ fulfilled_value }.tap(){ sleep(0.1) }
17
+ end
18
+
19
+ let(:rejected_subject) do
20
+ Future.new{ raise rejected_reason }.tap(){ sleep(0.1) }
21
+ end
22
+
23
+ before(:each) do
24
+ $GLOBAL_THREAD_POOL = FixedThreadPool.new(2)
25
+ end
26
+
27
+ it_should_behave_like Obligation
28
+
29
+ context 'behavior' do
30
+
31
+ it 'implements :future behavior' do
32
+ lambda {
33
+ Future.new{ nil }
34
+ }.should_not raise_error
35
+
36
+ Future.new{ nil }.behaves_as?(:future).should be_true
37
+ end
38
+ end
39
+
40
+ context '#initialize' do
41
+
42
+ it 'spawns a new thread when a block is given' do
43
+ $GLOBAL_THREAD_POOL.should_receive(:post).once.with(any_args())
44
+ Future.new{ nil }
45
+ end
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
+ it 'does not spawns a new thread when no block given' do
55
+ Thread.should_not_receive(:new).with(any_args())
56
+ Future.new
57
+ end
58
+
59
+ it 'immediately sets the state to :fulfilled when no block given' do
60
+ Future.new.should be_fulfilled
61
+ end
62
+
63
+ it 'immediately sets the value to nil when no block given' do
64
+ Future.new.value.should be_nil
65
+ end
66
+ end
67
+
68
+ context 'fulfillment' do
69
+
70
+ it 'passes all arguments to handler' do
71
+ @a = @b = @c = nil
72
+ f = Future.new(1, 2, 3) do |a, b, c|
73
+ @a, @b, @c = a, b, c
74
+ end
75
+ sleep(0.1)
76
+ [@a, @b, @c].should eq [1, 2, 3]
77
+ end
78
+
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
+ it 'sets the value to the result of the handler' do
90
+ f = Future.new(10){|a| a * 2 }
91
+ sleep(0.1)
92
+ f.value.should eq 20
93
+ end
94
+
95
+ it 'sets the state to :fulfilled when the block completes' do
96
+ f = Future.new(10){|a| a * 2 }
97
+ sleep(0.1)
98
+ f.should be_fulfilled
99
+ end
100
+
101
+ it 'sets the value to nil when the handler raises an exception' do
102
+ f = Future.new{ raise StandardError }
103
+ sleep(0.1)
104
+ f.value.should be_nil
105
+ end
106
+
107
+ it 'sets the state to :rejected when the handler raises an exception' do
108
+ f = Future.new{ raise StandardError }
109
+ sleep(0.1)
110
+ f.should be_rejected
111
+ end
112
+
113
+ context 'aliases' do
114
+
115
+ it 'aliases #realized? for #fulfilled?' do
116
+ fulfilled_subject.should be_realized
117
+ end
118
+
119
+ it 'aliases #deref for #value' do
120
+ fulfilled_subject.deref.should eq fulfilled_value
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -1,52 +1,67 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe '#go' do
6
-
7
- before(:each) do
8
- $GLOBAL_THREAD_POOL = CachedThreadPool.new
9
- end
10
-
11
- it 'passes all arguments to the block' do
12
- @expected = nil
13
- go(1, 2, 3){|a, b, c| @expected = [c, b, a] }
14
- sleep(0.1)
15
- @expected.should eq [3, 2, 1]
16
- end
17
-
18
- it 'returns true if the thread is successfully created' do
19
- $GLOBAL_THREAD_POOL.should_receive(:post).and_return(true)
20
- go{ nil }.should be_true
21
- end
22
-
23
- it 'returns false if the thread cannot be created' do
24
- $GLOBAL_THREAD_POOL.should_receive(:post).and_return(false)
25
- go{ nil }.should be_false
26
- end
27
-
28
- it 'immediately returns false if no block is given' do
29
- go().should be_false
30
- end
31
-
32
- it 'does not create a thread if no block is given' do
33
- $GLOBAL_THREAD_POOL.should_not_receive(:post)
34
- go()
35
- sleep(0.1)
36
- end
37
-
38
- it 'supresses exceptions on the thread' do
39
- lambda{
40
- go{ raise StandardError }
41
- sleep(0.1)
42
- }.should_not raise_error
43
- end
44
-
45
- it 'processes the block' do
46
- @expected = false
47
- go(1,2,3){|*args| @expected = args }
48
- sleep(0.1)
49
- @expected.should eq [1,2,3]
50
- end
51
- end
52
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe '#go' do
6
+
7
+ before(:each) do
8
+ $GLOBAL_THREAD_POOL = CachedThreadPool.new
9
+ end
10
+
11
+ it 'passes all arguments to the block' do
12
+ @expected = nil
13
+ go(1, 2, 3){|a, b, c| @expected = [c, b, a] }
14
+ sleep(0.1)
15
+ @expected.should eq [3, 2, 1]
16
+ end
17
+
18
+ it 'returns true if the thread is successfully created' do
19
+ $GLOBAL_THREAD_POOL.should_receive(:post).and_return(true)
20
+ go{ nil }.should be_true
21
+ end
22
+
23
+ it 'returns false if the thread cannot be created' do
24
+ $GLOBAL_THREAD_POOL.should_receive(:post).and_return(false)
25
+ go{ nil }.should be_false
26
+ end
27
+
28
+ it 'immediately returns false if no block is given' do
29
+ go().should be_false
30
+ end
31
+
32
+ it 'does not create a thread if no block is given' do
33
+ $GLOBAL_THREAD_POOL.should_not_receive(:post)
34
+ go()
35
+ sleep(0.1)
36
+ end
37
+
38
+ it 'supresses exceptions on the thread' do
39
+ lambda{
40
+ go{ raise StandardError }
41
+ sleep(0.1)
42
+ }.should_not raise_error
43
+ end
44
+
45
+ it 'processes the block' do
46
+ @expected = false
47
+ go(1,2,3){|*args| @expected = args }
48
+ sleep(0.1)
49
+ @expected.should eq [1,2,3]
50
+ end
51
+
52
+ it 'accepts an alternate thread pool as the first argument' do
53
+ pool = Concurrent::FixedThreadPool.new(2)
54
+ pool.should_receive(:post).with(no_args())
55
+ go(pool){ sleep(0.1) }
56
+ sleep(0.2)
57
+ end
58
+
59
+ it 'passes all other arguments to the block when a thread pool is given' do
60
+ @expected = nil
61
+ pool = Concurrent::FixedThreadPool.new(2)
62
+ go(pool, 1, 2, 3){|a, b, c| @expected = [c, b, a] }
63
+ sleep(0.1)
64
+ @expected.should eq [3, 2, 1]
65
+ end
66
+ end
67
+ end
@@ -1,121 +1,121 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- share_examples_for Obligation do
6
-
7
- context '#state' do
8
-
9
- it 'is :pending when first created' do
10
- f = pending_subject
11
- f.state.should == :pending
12
- f.should be_pending
13
- end
14
-
15
- it 'is :fulfilled when the handler completes' do
16
- f = fulfilled_subject
17
- f.state.should == :fulfilled
18
- f.should be_fulfilled
19
- end
20
-
21
- it 'is :rejected when the handler raises an exception' do
22
- f = rejected_subject
23
- f.state.should == :rejected
24
- f.should be_rejected
25
- end
26
- end
27
-
28
- context '#value' do
29
-
30
- it 'blocks the caller when :pending and timeout is nil' do
31
- f = pending_subject
32
- sleep(0.1)
33
- f.value.should be_true
34
- f.should be_fulfilled
35
- end
36
-
37
- it 'returns nil when reaching the optional timeout value' do
38
- f = pending_subject
39
- sleep(0.1)
40
- f.value(0.1).should be_nil
41
- f.should be_pending
42
- end
43
-
44
- it 'returns immediately when timeout is zero' do
45
- Timeout.should_not_receive(:timeout).with(any_args())
46
- f = pending_subject
47
- sleep(0.1)
48
- f.value(0).should be_nil
49
- f.should be_pending
50
- end
51
-
52
- it 'is nil when :pending' do
53
- expected = pending_subject.value
54
- expected.should be_nil
55
- end
56
-
57
- it 'is nil when :rejected' do
58
- expected = rejected_subject.value
59
- expected.should be_nil
60
- end
61
-
62
- it 'is set to the return value of the block when :fulfilled' do
63
- expected = fulfilled_subject.value
64
- expected.should eq fulfilled_value
65
- end
66
- end
67
-
68
- context '#reason' do
69
-
70
- it 'is nil when :pending' do
71
- pending_subject.reason.should be_nil
72
- end
73
-
74
- it 'is nil when :fulfilled' do
75
- fulfilled_subject.reason.should be_nil
76
- end
77
-
78
- it 'is set to error object of the exception when :rejected' do
79
- rejected_subject.reason.should be_a(Exception)
80
- rejected_subject.reason.to_s.should =~ /#{rejected_reason}/
81
- end
82
- end
83
-
84
- context 'Kernel aliases' do
85
-
86
- it 'aliases Kernel#deref for #deref' do
87
- deref(fulfilled_subject).should eq fulfilled_value
88
- deref(fulfilled_subject, 0).should eq fulfilled_value
89
- end
90
-
91
- it 'aliases Kernel#pending? for #pending?' do
92
- #NOTE: was structured like others but was incorrectly failing
93
- # on fulfilled_subject
94
- fulfilled_subject.should_receive(:pending?).once
95
- pending?(fulfilled_subject)
96
- pending_subject.should_receive(:pending?).once
97
- pending?(pending_subject)
98
- rejected_subject.should_receive(:pending?).once
99
- pending?(rejected_subject)
100
- end
101
-
102
- it 'aliases Kernel#fulfilled? for #fulfilled?' do
103
- fulfilled?(fulfilled_subject).should be_true
104
- fulfilled?(pending_subject).should be_false
105
- fulfilled?(rejected_subject).should be_false
106
- end
107
-
108
- it 'aliases Kernel#realized? for #realized?' do
109
- realized?(fulfilled_subject).should be_true
110
- realized?(pending_subject).should be_false
111
- realized?(rejected_subject).should be_false
112
- end
113
-
114
- it 'aliases Kernel#rejected? for #rejected?' do
115
- rejected?(rejected_subject).should be_true
116
- rejected?(fulfilled_subject).should be_false
117
- rejected?(pending_subject).should be_false
118
- end
119
- end
120
- end
121
- end
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ share_examples_for Obligation do
6
+
7
+ context '#state' do
8
+
9
+ it 'is :pending when first created' do
10
+ f = pending_subject
11
+ f.state.should == :pending
12
+ f.should be_pending
13
+ end
14
+
15
+ it 'is :fulfilled when the handler completes' do
16
+ f = fulfilled_subject
17
+ f.state.should == :fulfilled
18
+ f.should be_fulfilled
19
+ end
20
+
21
+ it 'is :rejected when the handler raises an exception' do
22
+ f = rejected_subject
23
+ f.state.should == :rejected
24
+ f.should be_rejected
25
+ end
26
+ end
27
+
28
+ context '#value' do
29
+
30
+ it 'blocks the caller when :pending and timeout is nil' do
31
+ f = pending_subject
32
+ sleep(0.1)
33
+ f.value.should be_true
34
+ f.should be_fulfilled
35
+ end
36
+
37
+ it 'returns nil when reaching the optional timeout value' do
38
+ f = pending_subject
39
+ sleep(0.1)
40
+ f.value(0.1).should be_nil
41
+ f.should be_pending
42
+ end
43
+
44
+ it 'returns immediately when timeout is zero' do
45
+ Timeout.should_not_receive(:timeout).with(any_args())
46
+ f = pending_subject
47
+ sleep(0.1)
48
+ f.value(0).should be_nil
49
+ f.should be_pending
50
+ end
51
+
52
+ it 'is nil when :pending' do
53
+ expected = pending_subject.value
54
+ expected.should be_nil
55
+ end
56
+
57
+ it 'is nil when :rejected' do
58
+ expected = rejected_subject.value
59
+ expected.should be_nil
60
+ end
61
+
62
+ it 'is set to the return value of the block when :fulfilled' do
63
+ expected = fulfilled_subject.value
64
+ expected.should eq fulfilled_value
65
+ end
66
+ end
67
+
68
+ context '#reason' do
69
+
70
+ it 'is nil when :pending' do
71
+ pending_subject.reason.should be_nil
72
+ end
73
+
74
+ it 'is nil when :fulfilled' do
75
+ fulfilled_subject.reason.should be_nil
76
+ end
77
+
78
+ it 'is set to error object of the exception when :rejected' do
79
+ rejected_subject.reason.should be_a(Exception)
80
+ rejected_subject.reason.to_s.should =~ /#{rejected_reason}/
81
+ end
82
+ end
83
+
84
+ context 'Kernel aliases' do
85
+
86
+ it 'aliases Kernel#deref for #deref' do
87
+ deref(fulfilled_subject).should eq fulfilled_value
88
+ deref(fulfilled_subject, 0).should eq fulfilled_value
89
+ end
90
+
91
+ it 'aliases Kernel#pending? for #pending?' do
92
+ #NOTE: was structured like others but was incorrectly failing
93
+ # on fulfilled_subject
94
+ fulfilled_subject.should_receive(:pending?).once
95
+ pending?(fulfilled_subject)
96
+ pending_subject.should_receive(:pending?).once
97
+ pending?(pending_subject)
98
+ rejected_subject.should_receive(:pending?).once
99
+ pending?(rejected_subject)
100
+ end
101
+
102
+ it 'aliases Kernel#fulfilled? for #fulfilled?' do
103
+ fulfilled?(fulfilled_subject).should be_true
104
+ fulfilled?(pending_subject).should be_false
105
+ fulfilled?(rejected_subject).should be_false
106
+ end
107
+
108
+ it 'aliases Kernel#realized? for #realized?' do
109
+ realized?(fulfilled_subject).should be_true
110
+ realized?(pending_subject).should be_false
111
+ realized?(rejected_subject).should be_false
112
+ end
113
+
114
+ it 'aliases Kernel#rejected? for #rejected?' do
115
+ rejected?(rejected_subject).should be_true
116
+ rejected?(fulfilled_subject).should be_false
117
+ rejected?(pending_subject).should be_false
118
+ end
119
+ end
120
+ end
121
+ end