concurrent-ruby 0.1.1.pre.3 → 0.1.1.pre.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -21
  3. data/README.md +275 -279
  4. data/lib/concurrent.rb +27 -28
  5. data/lib/concurrent/agent.rb +114 -108
  6. data/lib/concurrent/cached_thread_pool.rb +129 -130
  7. data/lib/concurrent/defer.rb +65 -67
  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 +93 -95
  11. data/lib/concurrent/fixed_thread_pool.rb +95 -89
  12. data/lib/concurrent/functions.rb +120 -120
  13. data/lib/concurrent/future.rb +42 -47
  14. data/lib/concurrent/global_thread_pool.rb +16 -16
  15. data/lib/concurrent/goroutine.rb +29 -29
  16. data/lib/concurrent/null_thread_pool.rb +22 -22
  17. data/lib/concurrent/obligation.rb +67 -67
  18. data/lib/concurrent/promise.rb +174 -166
  19. data/lib/concurrent/reactor.rb +161 -162
  20. data/lib/concurrent/reactor/drb_async_demux.rb +74 -74
  21. data/lib/concurrent/reactor/tcp_sync_demux.rb +98 -98
  22. data/lib/concurrent/thread_pool.rb +76 -69
  23. data/lib/concurrent/utilities.rb +32 -34
  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 +176 -176
  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 -380
  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 -253
  39. data/spec/concurrent/event_spec.rb +134 -134
  40. data/spec/concurrent/executor_spec.rb +184 -184
  41. data/spec/concurrent/fixed_thread_pool_spec.rb +83 -84
  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 +54 -54
  47. data/spec/concurrent/obligation_shared.rb +135 -121
  48. data/spec/concurrent/promise_spec.rb +312 -305
  49. data/spec/concurrent/reactor/drb_async_demux_spec.rb +12 -12
  50. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +12 -12
  51. data/spec/concurrent/reactor_spec.rb +351 -10
  52. data/spec/concurrent/thread_pool_shared.rb +209 -210
  53. data/spec/concurrent/utilities_spec.rb +74 -74
  54. data/spec/spec_helper.rb +44 -30
  55. metadata +11 -22
  56. data/lib/concurrent/smart_mutex.rb +0 -66
  57. data/spec/concurrent/smart_mutex_spec.rb +0 -234
@@ -1,89 +1,95 @@
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
- @status = :killed
30
- @pool.each{|t| Thread.kill(t) }
31
- end
32
-
33
- def size
34
- if running?
35
- return @pool.length
36
- else
37
- return 0
38
- end
39
- end
40
-
41
- def post(*args, &block)
42
- raise ArgumentError.new('no block given') unless block_given?
43
- if running?
44
- @queue << [args, block]
45
- return true
46
- else
47
- return false
48
- end
49
- end
50
-
51
- # @private
52
- def status # :nodoc:
53
- @pool.collect{|t| t.status }
54
- end
55
-
56
- private
57
-
58
- # @private
59
- def create_worker_thread # :nodoc:
60
- Thread.new do
61
- loop do
62
- task = @queue.pop
63
- if task == :stop
64
- break
65
- else
66
- task.last.call(*task.first)
67
- end
68
- end
69
- @pool.delete(Thread.current)
70
- if @pool.empty?
71
- @termination.set
72
- @status = :shutdown unless killed?
73
- end
74
- end
75
- end
76
-
77
- # @private
78
- def collect_garbage # :nodoc:
79
- @collector = Thread.new do
80
- sleep(1)
81
- @pool.size.times do |i|
82
- if @pool[i].status.nil?
83
- @pool[i] = create_worker_thread
84
- end
85
- end
86
- end
87
- end
88
- end
89
- 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.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,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,47 +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
- Thread.pass
23
- work(*args, &block)
24
- end
25
- end
26
- end
27
-
28
- private
29
-
30
- # @private
31
- def work(*args) # :nodoc:
32
- semaphore.synchronize do
33
- begin
34
- atomic {
35
- @value = yield(*args)
36
- @state = :fulfilled
37
- }
38
- rescue Exception => ex
39
- atomic {
40
- @state = :rejected
41
- @reason = ex
42
- }
43
- end
44
- end
45
- end
46
- end
47
- 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