concurrent-ruby 0.2.0 → 0.2.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 (57) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +275 -275
  3. data/lib/concurrent.rb +28 -28
  4. data/lib/concurrent/agent.rb +114 -114
  5. data/lib/concurrent/cached_thread_pool.rb +131 -129
  6. data/lib/concurrent/defer.rb +65 -65
  7. data/lib/concurrent/event.rb +60 -60
  8. data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
  9. data/lib/concurrent/executor.rb +96 -95
  10. data/lib/concurrent/fixed_thread_pool.rb +99 -95
  11. data/lib/concurrent/functions.rb +120 -120
  12. data/lib/concurrent/future.rb +42 -42
  13. data/lib/concurrent/global_thread_pool.rb +16 -16
  14. data/lib/concurrent/goroutine.rb +29 -29
  15. data/lib/concurrent/null_thread_pool.rb +22 -22
  16. data/lib/concurrent/obligation.rb +67 -67
  17. data/lib/concurrent/promise.rb +174 -174
  18. data/lib/concurrent/reactor.rb +166 -166
  19. data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
  20. data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
  21. data/lib/concurrent/supervisor.rb +105 -100
  22. data/lib/concurrent/thread_pool.rb +76 -76
  23. data/lib/concurrent/utilities.rb +32 -32
  24. data/lib/concurrent/version.rb +3 -3
  25. data/lib/concurrent_ruby.rb +1 -1
  26. data/md/agent.md +123 -123
  27. data/md/defer.md +174 -174
  28. data/md/event.md +32 -32
  29. data/md/executor.md +187 -187
  30. data/md/future.md +83 -83
  31. data/md/goroutine.md +52 -52
  32. data/md/obligation.md +32 -32
  33. data/md/promise.md +227 -227
  34. data/md/thread_pool.md +224 -224
  35. data/spec/concurrent/agent_spec.rb +386 -386
  36. data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
  37. data/spec/concurrent/defer_spec.rb +195 -195
  38. data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
  39. data/spec/concurrent/event_spec.rb +134 -134
  40. data/spec/concurrent/executor_spec.rb +200 -200
  41. data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
  42. data/spec/concurrent/functions_spec.rb +217 -217
  43. data/spec/concurrent/future_spec.rb +108 -108
  44. data/spec/concurrent/global_thread_pool_spec.rb +38 -38
  45. data/spec/concurrent/goroutine_spec.rb +67 -67
  46. data/spec/concurrent/null_thread_pool_spec.rb +57 -54
  47. data/spec/concurrent/obligation_shared.rb +132 -132
  48. data/spec/concurrent/promise_spec.rb +312 -312
  49. data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
  50. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
  51. data/spec/concurrent/reactor_spec.rb +364 -364
  52. data/spec/concurrent/supervisor_spec.rb +269 -258
  53. data/spec/concurrent/thread_pool_shared.rb +204 -204
  54. data/spec/concurrent/utilities_spec.rb +74 -74
  55. data/spec/spec_helper.rb +32 -32
  56. metadata +20 -16
  57. checksums.yaml +0 -7
@@ -1,95 +1,99 @@
1
- require 'thread'
2
-
3
- require 'concurrent/thread_pool'
4
- require 'concurrent/event'
5
-
6
- module Concurrent
7
-
8
- def self.new_fixed_thread_pool(size)
9
- return FixedThreadPool.new(size)
10
- end
11
-
12
- class FixedThreadPool < ThreadPool
13
- behavior(:thread_pool)
14
-
15
- MIN_POOL_SIZE = 1
16
- MAX_POOL_SIZE = 1024
17
-
18
- def initialize(size)
19
- super()
20
- if size < MIN_POOL_SIZE || size > MAX_POOL_SIZE
21
- raise ArgumentError.new("size must be between #{MIN_POOL_SIZE} and #{MAX_POOL_SIZE}")
22
- end
23
-
24
- @pool = size.times.collect{ create_worker_thread }
25
- collect_garbage
26
- end
27
-
28
- def kill
29
- mutex.synchronize do
30
- @status = :killed
31
- @pool.each{|t| Thread.kill(t) }
32
- end
33
- end
34
-
35
- def size
36
- if running?
37
- return @pool.length
38
- else
39
- return 0
40
- end
41
- end
42
-
43
- def post(*args, &block)
44
- raise ArgumentError.new('no block given') unless block_given?
45
- if running?
46
- @queue << [args, block]
47
- return true
48
- else
49
- return false
50
- end
51
- end
52
-
53
- # @private
54
- def status # :nodoc:
55
- mutex.synchronize do
56
- @pool.collect{|t| t.status }
57
- end
58
- end
59
-
60
- private
61
-
62
- # @private
63
- def create_worker_thread # :nodoc:
64
- Thread.new do
65
- loop do
66
- task = @queue.pop
67
- if task == :stop
68
- break
69
- else
70
- task.last.call(*task.first)
71
- end
72
- end
73
- @pool.delete(Thread.current)
74
- if @pool.empty?
75
- @termination.set
76
- @status = :shutdown unless killed?
77
- end
78
- end
79
- end
80
-
81
- # @private
82
- def collect_garbage # :nodoc:
83
- @collector = Thread.new do
84
- sleep(1)
85
- mutex.synchronize do
86
- @pool.size.times do |i|
87
- if @pool[i].status.nil?
88
- @pool[i] = create_worker_thread
89
- end
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end
1
+ require 'thread'
2
+
3
+ require 'concurrent/thread_pool'
4
+ require 'concurrent/event'
5
+
6
+ module Concurrent
7
+
8
+ def self.new_fixed_thread_pool(size)
9
+ return FixedThreadPool.new(size)
10
+ end
11
+
12
+ class FixedThreadPool < ThreadPool
13
+ behavior(:thread_pool)
14
+
15
+ MIN_POOL_SIZE = 1
16
+ MAX_POOL_SIZE = 1024
17
+
18
+ def initialize(size)
19
+ super()
20
+ if size < MIN_POOL_SIZE || size > MAX_POOL_SIZE
21
+ raise ArgumentError.new("size must be between #{MIN_POOL_SIZE} and #{MAX_POOL_SIZE}")
22
+ end
23
+
24
+ @pool = size.times.collect{ create_worker_thread }
25
+ collect_garbage
26
+ end
27
+
28
+ def kill
29
+ mutex.synchronize do
30
+ @status = :killed
31
+ @pool.each{|t| Thread.kill(t) }
32
+ end
33
+ end
34
+
35
+ def size
36
+ if running?
37
+ return @pool.length
38
+ else
39
+ return 0
40
+ end
41
+ end
42
+
43
+ def post(*args, &block)
44
+ raise ArgumentError.new('no block given') unless block_given?
45
+ if running?
46
+ @queue << [args, block]
47
+ return true
48
+ else
49
+ return false
50
+ end
51
+ end
52
+
53
+ # @private
54
+ def status # :nodoc:
55
+ mutex.synchronize do
56
+ @pool.collect{|t| t.status }
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ # @private
63
+ def create_worker_thread # :nodoc:
64
+ thread = Thread.new do
65
+ loop do
66
+ task = @queue.pop
67
+ if task == :stop
68
+ break
69
+ else
70
+ task.last.call(*task.first)
71
+ end
72
+ end
73
+ @pool.delete(Thread.current)
74
+ if @pool.empty?
75
+ @termination.set
76
+ @status = :shutdown unless killed?
77
+ end
78
+ end
79
+
80
+ thread.abort_on_exception = false
81
+ return thread
82
+ end
83
+
84
+ # @private
85
+ def collect_garbage # :nodoc:
86
+ @collector = Thread.new do
87
+ sleep(1)
88
+ mutex.synchronize do
89
+ @pool.size.times do |i|
90
+ if @pool[i].status.nil?
91
+ @pool[i] = create_worker_thread
92
+ end
93
+ end
94
+ end
95
+ end
96
+ @collector.abort_on_exception = false
97
+ end
98
+ end
99
+ end
@@ -1,120 +1,120 @@
1
- require 'concurrent/agent'
2
- require 'concurrent/defer'
3
- require 'concurrent/future'
4
- require 'concurrent/promise'
5
-
6
- module Kernel
7
-
8
- ## agent
9
-
10
- def agent(initial, timeout = Concurrent::Agent::TIMEOUT)
11
- return Concurrent::Agent.new(initial, timeout)
12
- end
13
- module_function :agent
14
-
15
- def post(object, &block)
16
- if object.respond_to?(:post)
17
- return object.post(&block)
18
- else
19
- raise ArgumentError.new('object does not support #post')
20
- end
21
- end
22
- module_function :post
23
-
24
- ## defer
25
-
26
- def defer(*args, &block)
27
- return Concurrent::Defer.new(*args, &block)
28
- end
29
- module_function :defer
30
-
31
- ## executor
32
-
33
- def executor(*args, &block)
34
- return Concurrent::Executor.run(*args, &block)
35
- end
36
- module_function :executor
37
-
38
- ## future
39
-
40
- def future(*args, &block)
41
- return Concurrent::Future.new(*args, &block)
42
- end
43
- module_function :future
44
-
45
- ## obligation
46
-
47
- def deref(object, timeout = nil)
48
- if object.respond_to?(:deref)
49
- return object.deref(timeout)
50
- elsif object.respond_to?(:value)
51
- return object.value(timeout)
52
- else
53
- raise ArgumentError.new('object does not support #deref')
54
- end
55
- end
56
- module_function :deref
57
-
58
- def pending?(object)
59
- if object.respond_to?(:pending?)
60
- return object.pending?
61
- else
62
- raise ArgumentError.new('object does not support #pending?')
63
- end
64
- end
65
- module_function :pending?
66
-
67
- def fulfilled?(object)
68
- if object.respond_to?(:fulfilled?)
69
- return object.fulfilled?
70
- elsif object.respond_to?(:realized?)
71
- return object.realized?
72
- else
73
- raise ArgumentError.new('object does not support #fulfilled?')
74
- end
75
- end
76
- module_function :fulfilled?
77
-
78
- def realized?(object)
79
- if object.respond_to?(:realized?)
80
- return object.realized?
81
- elsif object.respond_to?(:fulfilled?)
82
- return object.fulfilled?
83
- else
84
- raise ArgumentError.new('object does not support #realized?')
85
- end
86
- end
87
- module_function :realized?
88
-
89
- def rejected?(object)
90
- if object.respond_to?(:rejected?)
91
- return object.rejected?
92
- else
93
- raise ArgumentError.new('object does not support #rejected?')
94
- end
95
- end
96
- module_function :rejected?
97
-
98
- ## promise
99
-
100
- # Creates a new promise object. "A promise represents the eventual
101
- # value returned from the single completion of an operation."
102
- # Promises can be chained in a tree structure where each promise
103
- # has zero or more children. Promises are resolved asynchronously
104
- # in the order they are added to the tree. Parents are guaranteed
105
- # to be resolved before their children. The result of each promise
106
- # is passes to each of its children when the child resolves. When
107
- # a promise is rejected all its children will be summarily rejected.
108
- # A promise added to a rejected promise will immediately be rejected.
109
- # A promise that is neither resolved or rejected is pending.
110
- #
111
- # @param args [Array] zero or more arguments for the block
112
- # @param block [Proc] the block to call when attempting fulfillment
113
- #
114
- # @see Promise
115
- # @see http://wiki.commonjs.org/wiki/Promises/A
116
- def promise(*args, &block)
117
- return Concurrent::Promise.new(*args, &block)
118
- end
119
- module_function :promise
120
- end
1
+ require 'concurrent/agent'
2
+ require 'concurrent/defer'
3
+ require 'concurrent/future'
4
+ require 'concurrent/promise'
5
+
6
+ module Kernel
7
+
8
+ ## agent
9
+
10
+ def agent(initial, timeout = Concurrent::Agent::TIMEOUT)
11
+ return Concurrent::Agent.new(initial, timeout)
12
+ end
13
+ module_function :agent
14
+
15
+ def post(object, &block)
16
+ if object.respond_to?(:post)
17
+ return object.post(&block)
18
+ else
19
+ raise ArgumentError.new('object does not support #post')
20
+ end
21
+ end
22
+ module_function :post
23
+
24
+ ## defer
25
+
26
+ def defer(*args, &block)
27
+ return Concurrent::Defer.new(*args, &block)
28
+ end
29
+ module_function :defer
30
+
31
+ ## executor
32
+
33
+ def executor(*args, &block)
34
+ return Concurrent::Executor.run(*args, &block)
35
+ end
36
+ module_function :executor
37
+
38
+ ## future
39
+
40
+ def future(*args, &block)
41
+ return Concurrent::Future.new(*args, &block)
42
+ end
43
+ module_function :future
44
+
45
+ ## obligation
46
+
47
+ def deref(object, timeout = nil)
48
+ if object.respond_to?(:deref)
49
+ return object.deref(timeout)
50
+ elsif object.respond_to?(:value)
51
+ return object.value(timeout)
52
+ else
53
+ raise ArgumentError.new('object does not support #deref')
54
+ end
55
+ end
56
+ module_function :deref
57
+
58
+ def pending?(object)
59
+ if object.respond_to?(:pending?)
60
+ return object.pending?
61
+ else
62
+ raise ArgumentError.new('object does not support #pending?')
63
+ end
64
+ end
65
+ module_function :pending?
66
+
67
+ def fulfilled?(object)
68
+ if object.respond_to?(:fulfilled?)
69
+ return object.fulfilled?
70
+ elsif object.respond_to?(:realized?)
71
+ return object.realized?
72
+ else
73
+ raise ArgumentError.new('object does not support #fulfilled?')
74
+ end
75
+ end
76
+ module_function :fulfilled?
77
+
78
+ def realized?(object)
79
+ if object.respond_to?(:realized?)
80
+ return object.realized?
81
+ elsif object.respond_to?(:fulfilled?)
82
+ return object.fulfilled?
83
+ else
84
+ raise ArgumentError.new('object does not support #realized?')
85
+ end
86
+ end
87
+ module_function :realized?
88
+
89
+ def rejected?(object)
90
+ if object.respond_to?(:rejected?)
91
+ return object.rejected?
92
+ else
93
+ raise ArgumentError.new('object does not support #rejected?')
94
+ end
95
+ end
96
+ module_function :rejected?
97
+
98
+ ## promise
99
+
100
+ # Creates a new promise object. "A promise represents the eventual
101
+ # value returned from the single completion of an operation."
102
+ # Promises can be chained in a tree structure where each promise
103
+ # has zero or more children. Promises are resolved asynchronously
104
+ # in the order they are added to the tree. Parents are guaranteed
105
+ # to be resolved before their children. The result of each promise
106
+ # is passes to each of its children when the child resolves. When
107
+ # a promise is rejected all its children will be summarily rejected.
108
+ # A promise added to a rejected promise will immediately be rejected.
109
+ # A promise that is neither resolved or rejected is pending.
110
+ #
111
+ # @param args [Array] zero or more arguments for the block
112
+ # @param block [Proc] the block to call when attempting fulfillment
113
+ #
114
+ # @see Promise
115
+ # @see http://wiki.commonjs.org/wiki/Promises/A
116
+ def promise(*args, &block)
117
+ return Concurrent::Promise.new(*args, &block)
118
+ end
119
+ module_function :promise
120
+ end
@@ -1,42 +1,42 @@
1
- require 'thread'
2
-
3
- require 'concurrent/global_thread_pool'
4
- require 'concurrent/obligation'
5
- require 'concurrent/utilities'
6
-
7
- module Concurrent
8
-
9
- class Future
10
- include Obligation
11
- include UsesGlobalThreadPool
12
-
13
- behavior(:future)
14
-
15
- def initialize(*args, &block)
16
- unless block_given?
17
- @state = :fulfilled
18
- else
19
- @value = nil
20
- @state = :pending
21
- Future.thread_pool.post(*args) do
22
- work(*args, &block)
23
- end
24
- end
25
- end
26
-
27
- private
28
-
29
- # @private
30
- def work(*args) # :nodoc:
31
- mutex.synchronize do
32
- begin
33
- @value = yield(*args)
34
- @state = :fulfilled
35
- rescue Exception => ex
36
- @state = :rejected
37
- @reason = ex
38
- end
39
- end
40
- end
41
- end
42
- end
1
+ require 'thread'
2
+
3
+ require 'concurrent/global_thread_pool'
4
+ require 'concurrent/obligation'
5
+ require 'concurrent/utilities'
6
+
7
+ module Concurrent
8
+
9
+ class Future
10
+ include Obligation
11
+ include UsesGlobalThreadPool
12
+
13
+ behavior(:future)
14
+
15
+ def initialize(*args, &block)
16
+ unless block_given?
17
+ @state = :fulfilled
18
+ else
19
+ @value = nil
20
+ @state = :pending
21
+ Future.thread_pool.post(*args) do
22
+ work(*args, &block)
23
+ end
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ # @private
30
+ def work(*args) # :nodoc:
31
+ mutex.synchronize do
32
+ begin
33
+ @value = yield(*args)
34
+ @state = :fulfilled
35
+ rescue Exception => ex
36
+ @state = :rejected
37
+ @reason = ex
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end