concurrent-ruby 0.1.0 → 0.1.1.pre.1

Sign up to get free protection for your applications and to get access to all the features.
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