concurrent-ruby 0.8.0 → 0.9.0.pre2

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -2
  3. data/README.md +103 -54
  4. data/lib/concurrent.rb +34 -14
  5. data/lib/concurrent/async.rb +164 -50
  6. data/lib/concurrent/atom.rb +171 -0
  7. data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
  8. data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
  9. data/lib/concurrent/atomic/atomic_reference.rb +49 -0
  10. data/lib/concurrent/atomic/condition.rb +23 -12
  11. data/lib/concurrent/atomic/count_down_latch.rb +23 -21
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
  13. data/lib/concurrent/atomic/event.rb +33 -42
  14. data/lib/concurrent/atomic/read_write_lock.rb +252 -0
  15. data/lib/concurrent/atomic/semaphore.rb +64 -89
  16. data/lib/concurrent/atomic/thread_local_var.rb +130 -58
  17. data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
  18. data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
  21. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
  22. data/lib/concurrent/atomic_reference/rbx.rb +4 -1
  23. data/lib/concurrent/atomic_reference/ruby.rb +6 -3
  24. data/lib/concurrent/atomics.rb +74 -4
  25. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
  26. data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
  27. data/lib/concurrent/collection/priority_queue.rb +300 -245
  28. data/lib/concurrent/concern/deprecation.rb +27 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +25 -0
  31. data/lib/concurrent/concern/obligation.rb +228 -0
  32. data/lib/concurrent/concern/observable.rb +85 -0
  33. data/lib/concurrent/configuration.rb +226 -112
  34. data/lib/concurrent/dataflow.rb +2 -3
  35. data/lib/concurrent/delay.rb +141 -50
  36. data/lib/concurrent/edge.rb +30 -0
  37. data/lib/concurrent/errors.rb +10 -0
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
  40. data/lib/concurrent/executor/executor.rb +46 -299
  41. data/lib/concurrent/executor/executor_service.rb +521 -0
  42. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
  43. data/lib/concurrent/executor/immediate_executor.rb +9 -9
  44. data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
  45. data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
  46. data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
  47. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  48. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  49. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
  50. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
  51. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  52. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  53. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  54. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  55. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  56. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  57. data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
  58. data/lib/concurrent/executor/timer_set.rb +96 -84
  59. data/lib/concurrent/executors.rb +1 -1
  60. data/lib/concurrent/future.rb +70 -38
  61. data/lib/concurrent/immutable_struct.rb +89 -0
  62. data/lib/concurrent/ivar.rb +152 -60
  63. data/lib/concurrent/lazy_register.rb +40 -20
  64. data/lib/concurrent/maybe.rb +226 -0
  65. data/lib/concurrent/mutable_struct.rb +227 -0
  66. data/lib/concurrent/mvar.rb +44 -43
  67. data/lib/concurrent/promise.rb +208 -134
  68. data/lib/concurrent/scheduled_task.rb +339 -43
  69. data/lib/concurrent/settable_struct.rb +127 -0
  70. data/lib/concurrent/synchronization.rb +17 -0
  71. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  72. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  73. data/lib/concurrent/synchronization/condition.rb +53 -0
  74. data/lib/concurrent/synchronization/java_object.rb +35 -0
  75. data/lib/concurrent/synchronization/lock.rb +32 -0
  76. data/lib/concurrent/synchronization/monitor_object.rb +24 -0
  77. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  78. data/lib/concurrent/synchronization/object.rb +78 -0
  79. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  80. data/lib/concurrent/timer_task.rb +87 -100
  81. data/lib/concurrent/tvar.rb +42 -38
  82. data/lib/concurrent/utilities.rb +3 -1
  83. data/lib/concurrent/utility/at_exit.rb +97 -0
  84. data/lib/concurrent/utility/engine.rb +40 -0
  85. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  86. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  87. data/lib/concurrent/utility/processor_counter.rb +156 -0
  88. data/lib/concurrent/utility/timeout.rb +18 -14
  89. data/lib/concurrent/utility/timer.rb +11 -6
  90. data/lib/concurrent/version.rb +2 -1
  91. data/lib/concurrent_ruby.rb +1 -0
  92. metadata +47 -83
  93. data/lib/concurrent/actor.rb +0 -103
  94. data/lib/concurrent/actor/behaviour.rb +0 -70
  95. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  96. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  97. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  98. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  99. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  100. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  101. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  102. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  103. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  104. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  105. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  106. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  107. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  108. data/lib/concurrent/actor/context.rb +0 -154
  109. data/lib/concurrent/actor/core.rb +0 -217
  110. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  111. data/lib/concurrent/actor/envelope.rb +0 -41
  112. data/lib/concurrent/actor/errors.rb +0 -27
  113. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  114. data/lib/concurrent/actor/public_delegations.rb +0 -40
  115. data/lib/concurrent/actor/reference.rb +0 -81
  116. data/lib/concurrent/actor/root.rb +0 -37
  117. data/lib/concurrent/actor/type_check.rb +0 -48
  118. data/lib/concurrent/actor/utils.rb +0 -10
  119. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  120. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  121. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  122. data/lib/concurrent/actor/utils/pool.rb +0 -59
  123. data/lib/concurrent/actress.rb +0 -3
  124. data/lib/concurrent/agent.rb +0 -209
  125. data/lib/concurrent/atomic.rb +0 -92
  126. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  127. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  128. data/lib/concurrent/atomic/synchronization.rb +0 -51
  129. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  130. data/lib/concurrent/channel/channel.rb +0 -41
  131. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  132. data/lib/concurrent/channel/waitable_list.rb +0 -40
  133. data/lib/concurrent/channels.rb +0 -5
  134. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  135. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  136. data/lib/concurrent/collections.rb +0 -3
  137. data/lib/concurrent/dereferenceable.rb +0 -108
  138. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  139. data/lib/concurrent/logging.rb +0 -20
  140. data/lib/concurrent/obligation.rb +0 -171
  141. data/lib/concurrent/observable.rb +0 -73
  142. data/lib/concurrent/options_parser.rb +0 -52
  143. data/lib/concurrent/utility/processor_count.rb +0 -152
  144. data/lib/extension_helper.rb +0 -37
@@ -1,73 +0,0 @@
1
- require 'thread'
2
- require 'concurrent/logging'
3
-
4
- module Concurrent
5
-
6
- # @!visibility private
7
- class RubyThreadPoolWorker
8
- include Logging
9
-
10
- # @!visibility private
11
- def initialize(queue, parent)
12
- @queue = queue
13
- @parent = parent
14
- @mutex = Mutex.new
15
- @last_activity = Time.now.to_f
16
- @thread = nil
17
- end
18
-
19
- # @!visibility private
20
- def dead?
21
- return @mutex.synchronize do
22
- @thread.nil? ? false : ! @thread.alive?
23
- end
24
- end
25
-
26
- # @!visibility private
27
- def last_activity
28
- @mutex.synchronize { @last_activity }
29
- end
30
-
31
- def status
32
- @mutex.synchronize do
33
- return 'not running' if @thread.nil?
34
- @thread.status
35
- end
36
- end
37
-
38
- # @!visibility private
39
- def kill
40
- @mutex.synchronize do
41
- Thread.kill(@thread) unless @thread.nil?
42
- @thread = nil
43
- end
44
- end
45
-
46
- # @!visibility private
47
- def run(thread = Thread.current)
48
- @mutex.synchronize do
49
- raise StandardError.new('already running') unless @thread.nil?
50
- @thread = thread
51
- end
52
-
53
- loop do
54
- task = @queue.pop
55
- if task == :stop
56
- @thread = nil
57
- @parent.on_worker_exit(self)
58
- break
59
- end
60
-
61
- begin
62
- task.last.call(*task.first)
63
- rescue => ex
64
- # let it fail
65
- log DEBUG, ex
66
- ensure
67
- @last_activity = Time.now.to_f
68
- @parent.on_end_task
69
- end
70
- end
71
- end
72
- end
73
- end
@@ -1,20 +0,0 @@
1
- require 'logger'
2
-
3
- module Concurrent
4
- # Include where logging is needed
5
- module Logging
6
- include Logger::Severity
7
-
8
- # Logs through {Configuration#logger}, it can be overridden by setting @logger
9
- # @param [Integer] level one of Logger::Severity constants
10
- # @param [String] progname e.g. a path of an Actor
11
- # @param [String, nil] message when nil block is used to generate the message
12
- # @yieldreturn [String] a message
13
- def log(level, progname, message = nil, &block)
14
- (@logger || Concurrent.configuration.logger).call level, progname, message, &block
15
- rescue => error
16
- $stderr.puts "`Concurrent.configuration.logger` failed to log #{[level, progname, message, block]}\n" +
17
- "#{error.message} (#{error.class})\n#{error.backtrace.join "\n"}"
18
- end
19
- end
20
- end
@@ -1,171 +0,0 @@
1
- require 'thread'
2
- require 'timeout'
3
-
4
- require 'concurrent/dereferenceable'
5
- require 'concurrent/atomic/event'
6
-
7
- module Concurrent
8
-
9
- module Obligation
10
- include Dereferenceable
11
-
12
- # Has the obligation been fulfilled?
13
- # @return [Boolean]
14
- def fulfilled?
15
- state == :fulfilled
16
- end
17
- alias_method :realized?, :fulfilled?
18
-
19
- # Has the obligation been rejected?
20
- # @return [Boolean]
21
- def rejected?
22
- state == :rejected
23
- end
24
-
25
- # Is obligation completion still pending?
26
- # @return [Boolean]
27
- def pending?
28
- state == :pending
29
- end
30
-
31
- # Is the obligation still unscheduled?
32
- # @return [Boolean]
33
- def unscheduled?
34
- state == :unscheduled
35
- end
36
-
37
- def completed?
38
- [:fulfilled, :rejected].include? state
39
- end
40
-
41
- def incomplete?
42
- [:unscheduled, :pending].include? state
43
- end
44
-
45
- # @return [Object] see Dereferenceable#deref
46
- def value(timeout = nil)
47
- wait timeout
48
- deref
49
- end
50
-
51
- # wait until Obligation is #complete?
52
- # @param [Numeric] timeout the maximum time in second to wait.
53
- # @return [Obligation] self
54
- def wait(timeout = nil)
55
- event.wait(timeout) if timeout != 0 && incomplete?
56
- self
57
- end
58
-
59
- # wait until Obligation is #complete?
60
- # @param [Numeric] timeout the maximum time in second to wait.
61
- # @return [Obligation] self
62
- # @raise [Exception] when #rejected? it raises #reason
63
- def no_error!(timeout = nil)
64
- wait(timeout).tap { raise self if rejected? }
65
- end
66
-
67
- # @raise [Exception] when #rejected? it raises #reason
68
- # @return [Object] see Dereferenceable#deref
69
- def value!(timeout = nil)
70
- wait(timeout)
71
- if rejected?
72
- raise self
73
- else
74
- deref
75
- end
76
- end
77
-
78
- def state
79
- mutex.lock
80
- @state
81
- ensure
82
- mutex.unlock
83
- end
84
-
85
- def reason
86
- mutex.lock
87
- @reason
88
- ensure
89
- mutex.unlock
90
- end
91
-
92
- # @example allows Obligation to be risen
93
- # rejected_ivar = Ivar.new.fail
94
- # raise rejected_ivar
95
- def exception(*args)
96
- raise 'obligation is not rejected' unless rejected?
97
- reason.exception(*args)
98
- end
99
-
100
- protected
101
-
102
- # @!visibility private
103
- def init_obligation # :nodoc:
104
- init_mutex
105
- @event = Event.new
106
- end
107
-
108
- # @!visibility private
109
- def event # :nodoc:
110
- @event
111
- end
112
-
113
- # @!visibility private
114
- def set_state(success, value, reason) # :nodoc:
115
- if success
116
- @value = value
117
- @state = :fulfilled
118
- else
119
- @reason = reason
120
- @state = :rejected
121
- end
122
- end
123
-
124
- # @!visibility private
125
- def state=(value) # :nodoc:
126
- mutex.lock
127
- @state = value
128
- ensure
129
- mutex.unlock
130
- end
131
-
132
- # atomic compare and set operation
133
- # state is set to next_state only if current state is == expected_current
134
- #
135
- # @param [Symbol] next_state
136
- # @param [Symbol] expected_current
137
- #
138
- # @return [Boolean] true is state is changed, false otherwise
139
- #
140
- # @!visibility private
141
- def compare_and_set_state(next_state, expected_current) # :nodoc:
142
- mutex.lock
143
- if @state == expected_current
144
- @state = next_state
145
- true
146
- else
147
- false
148
- end
149
- ensure
150
- mutex.unlock
151
- end
152
-
153
- # executes the block within mutex if current state is included in expected_states
154
- #
155
- # @return block value if executed, false otherwise
156
- #
157
- # @!visibility private
158
- def if_state(*expected_states) # :nodoc:
159
- mutex.lock
160
- raise ArgumentError.new('no block given') unless block_given?
161
-
162
- if expected_states.include? @state
163
- yield
164
- else
165
- false
166
- end
167
- ensure
168
- mutex.unlock
169
- end
170
- end
171
- end
@@ -1,73 +0,0 @@
1
- require 'concurrent/atomic/copy_on_notify_observer_set'
2
- require 'concurrent/atomic/copy_on_write_observer_set'
3
-
4
- module Concurrent
5
-
6
- # The [observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) is one of the most useful design pattern.
7
- #
8
- # The workflow is very simple:
9
- # - an `observer` can register itself to a `subject` via a callback
10
- # - many `observers` can be registered to the same `subject`
11
- # - the `subject` notifies all registered observers when its status changes
12
- # - an `observer` can deregister itself when is no more interested to receive event notifications
13
- #
14
- # In a single threaded environment the whole pattern is very easy: the `subject` can use a simple data structure to manage all its subscribed `observer`s and every `observer` can react directly to every event without caring about synchronization.
15
- #
16
- # In a multi threaded environment things are more complex.
17
- # The `subject` must synchronize the access to its data structure and to do so currently we're using two specialized ObserverSet: CopyOnWriteObserverSet and CopyOnNotifyObserverSet.
18
- #
19
- # When implementing and `observer` there's a very important rule to remember: **there are no guarantees about the thread that will execute the callback**
20
- #
21
- # Let's take this example
22
- # ```
23
- # class Observer
24
- # def initialize
25
- # @count = 0
26
- # end
27
- #
28
- # def update
29
- # @count += 1
30
- # end
31
- # end
32
- #
33
- # obs = Observer.new
34
- # [obj1, obj2, obj3, obj4].each { |o| o.add_observer(obs) }
35
- # # execute [obj1, obj2, obj3, obj4]
36
- # ```
37
- #
38
- # `obs` is wrong because the variable `@count` can be accessed by different threads at the same time, so it should be synchronized (using either a Mutex or an AtomicFixum)
39
- module Observable
40
-
41
- # @return [Object] the added observer
42
- def add_observer(*args, &block)
43
- observers.add_observer(*args, &block)
44
- end
45
-
46
- # as #add_observer but it can be used for chaining
47
- # @return [Observable] self
48
- def with_observer(*args, &block)
49
- add_observer(*args, &block)
50
- self
51
- end
52
-
53
- # @return [Object] the deleted observer
54
- def delete_observer(*args)
55
- observers.delete_observer(*args)
56
- end
57
-
58
- # @return [Observable] self
59
- def delete_observers
60
- observers.delete_observers
61
- self
62
- end
63
-
64
- # @return [Integer] the observers count
65
- def count_observers
66
- observers.count_observers
67
- end
68
-
69
- protected
70
-
71
- attr_accessor :observers
72
- end
73
- end
@@ -1,52 +0,0 @@
1
- module Concurrent
2
-
3
- # A mixin module for parsing options hashes related to gem-level configuration.
4
- module OptionsParser
5
-
6
- # Get the requested `Executor` based on the values set in the options hash.
7
- #
8
- # @param [Hash] opts the options defining the requested executor
9
- # @option opts [Executor] :executor (`nil`) when set use the given `Executor` instance
10
- # @option opts [Boolean] :operation (`false`) when true use the global operation pool
11
- # @option opts [Boolean] :task (`true`) when true use the global task pool
12
- #
13
- # @return [Executor, nil] the requested thread pool, or nil when no option specified
14
- def get_executor_from(opts = {})
15
- if opts[:executor]
16
- opts[:executor]
17
- elsif opts[:operation] == true || opts[:task] == false
18
- Concurrent.configuration.global_operation_pool
19
- elsif opts[:operation] == false || opts[:task] == true
20
- Concurrent.configuration.global_task_pool
21
- else
22
- nil
23
- end
24
- end
25
-
26
- def get_arguments_from(opts = {})
27
- [*opts.fetch(:args, [])]
28
- end
29
-
30
- # Get the requested `Executor` based on the values set in the options hash.
31
- #
32
- # @param [Hash] opts the options defining the requested executor
33
- # @option opts [Executor] :task_executor (`nil`) when set use the given `Executor` instance
34
- #
35
- # @return [Executor] the requested thread pool (default: global task pool)
36
- def get_task_executor_from(opts = {})
37
- opts[:task_executor] || opts[:executor] || Concurrent.configuration.global_task_pool
38
- end
39
-
40
- # Get the requested `Executor` based on the values set in the options hash.
41
- #
42
- # @param [Hash] opts the options defining the requested executor
43
- # @option opts [Executor] :task_executor (`nil`) when set use the given `Executor` instance
44
- #
45
- # @return [Executor] the requested thread pool (default: global operation pool)
46
- def get_operation_executor_from(opts = {})
47
- opts[:operation_executor] || opts[:executor] || Concurrent.configuration.global_operation_pool
48
- end
49
-
50
- extend self
51
- end
52
- end
@@ -1,152 +0,0 @@
1
- require 'rbconfig'
2
- require 'concurrent/delay'
3
- require 'concurrent/executor/immediate_executor'
4
-
5
- module Concurrent
6
-
7
- class ProcessorCounter
8
- def initialize
9
- immediate_executor = ImmediateExecutor.new
10
- @processor_count = Delay.new(executor: immediate_executor) { compute_processor_count }
11
- @physical_processor_count = Delay.new(executor: immediate_executor) { compute_physical_processor_count }
12
- end
13
-
14
- # Number of processors seen by the OS and used for process scheduling. For performance
15
- # reasons the calculated value will be memoized on the first call.
16
- #
17
- # When running under JRuby the Java runtime call `java.lang.Runtime.getRuntime.availableProcessors`
18
- # will be used. According to the Java documentation this "value may change
19
- # during a particular invocation of the virtual machine... [applications]
20
- # should therefore occasionally poll this property." Subsequently the result
21
- # will NOT be memoized under JRuby.
22
- #
23
- # On Windows the Win32 API will be queried for the `NumberOfLogicalProcessors from Win32_Processor`.
24
- # This will return the total number "logical processors for the current instance of the processor",
25
- # which taked into account hyperthreading.
26
- #
27
- # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev
28
- # * BSD: /sbin/sysctl
29
- # * Cygwin: /proc/cpuinfo
30
- # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl
31
- # * HP-UX: /usr/sbin/ioscan
32
- # * IRIX: /usr/sbin/sysconf
33
- # * Linux: /proc/cpuinfo
34
- # * Minix 3+: /proc/cpuinfo
35
- # * Solaris: /usr/sbin/psrinfo
36
- # * Tru64 UNIX: /usr/sbin/psrinfo
37
- # * UnixWare: /usr/sbin/psrinfo
38
- #
39
- # @return [Integer] number of processors seen by the OS or Java runtime
40
- #
41
- # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
42
- #
43
- # @see http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#availableProcessors()
44
- # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
45
- def processor_count
46
- @processor_count.value
47
- end
48
-
49
- # Number of physical processor cores on the current system. For performance reasons
50
- # the calculated value will be memoized on the first call.
51
- #
52
- # On Windows the Win32 API will be queried for the `NumberOfCores from Win32_Processor`.
53
- # This will return the total number "of cores for the current instance of the processor."
54
- # On Unix-like operating systems either the `hwprefs` or `sysctl` utility will be called
55
- # in a subshell and the returned value will be used. In the rare case where none of these
56
- # methods work or an exception is raised the function will simply return 1.
57
- #
58
- # @return [Integer] number physical processor cores on the current system
59
- #
60
- # @see https://github.com/grosser/parallel/blob/4fc8b89d08c7091fe0419ca8fba1ec3ce5a8d185/lib/parallel.rb
61
- #
62
- # @see http://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx
63
- # @see http://www.unix.com/man-page/osx/1/HWPREFS/
64
- # @see http://linux.die.net/man/8/sysctl
65
- def physical_processor_count
66
- @physical_processor_count.value
67
- end
68
-
69
- private
70
-
71
- def compute_processor_count
72
- if RUBY_PLATFORM == 'java'
73
- java.lang.Runtime.getRuntime.availableProcessors
74
- else
75
- os_name = RbConfig::CONFIG["target_os"]
76
- if os_name =~ /mingw|mswin/
77
- require 'win32ole'
78
- result = WIN32OLE.connect("winmgmts://").ExecQuery(
79
- "select NumberOfLogicalProcessors from Win32_Processor")
80
- result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
81
- elsif File.readable?("/proc/cpuinfo")
82
- IO.read("/proc/cpuinfo").scan(/^processor/).size
83
- elsif File.executable?("/usr/bin/hwprefs")
84
- IO.popen("/usr/bin/hwprefs thread_count").read.to_i
85
- elsif File.executable?("/usr/sbin/psrinfo")
86
- IO.popen("/usr/sbin/psrinfo").read.scan(/^.*on-*line/).size
87
- elsif File.executable?("/usr/sbin/ioscan")
88
- IO.popen("/usr/sbin/ioscan -kC processor") do |out|
89
- out.read.scan(/^.*processor/).size
90
- end
91
- elsif File.executable?("/usr/sbin/pmcycles")
92
- IO.popen("/usr/sbin/pmcycles -m").read.count("\n")
93
- elsif File.executable?("/usr/sbin/lsdev")
94
- IO.popen("/usr/sbin/lsdev -Cc processor -S 1").read.count("\n")
95
- elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
96
- IO.popen("/usr/sbin/sysconf NPROC_ONLN").read.to_i
97
- elsif File.executable?("/usr/sbin/sysctl")
98
- IO.popen("/usr/sbin/sysctl -n hw.ncpu").read.to_i
99
- elsif File.executable?("/sbin/sysctl")
100
- IO.popen("/sbin/sysctl -n hw.ncpu").read.to_i
101
- else
102
- 1
103
- end
104
- end
105
- rescue
106
- return 1
107
- end
108
-
109
- def compute_physical_processor_count
110
- ppc = case RbConfig::CONFIG["target_os"]
111
- when /darwin1/
112
- IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
113
- when /linux/
114
- cores = {} # unique physical ID / core ID combinations
115
- phy = 0
116
- IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
117
- if ln.start_with?("physical")
118
- phy = ln[/\d+/]
119
- elsif ln.start_with?("core")
120
- cid = phy + ":" + ln[/\d+/]
121
- cores[cid] = true if not cores[cid]
122
- end
123
- end
124
- cores.count
125
- when /mswin|mingw/
126
- require 'win32ole'
127
- result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
128
- "select NumberOfCores from Win32_Processor")
129
- result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
130
- else
131
- processor_count
132
- end
133
- # fall back to logical count if physical info is invalid
134
- ppc > 0 ? ppc : processor_count
135
- rescue
136
- return 1
137
- end
138
- end
139
-
140
- # create the default ProcessorCounter on load
141
- @processor_counter = ProcessorCounter.new
142
- singleton_class.send :attr_reader, :processor_counter
143
-
144
- def self.processor_count
145
- processor_counter.processor_count
146
- end
147
-
148
- def self.physical_processor_count
149
- processor_counter.physical_processor_count
150
- end
151
-
152
- end