[DRE-commits] [ruby-parallel] 01/13: New upstream version 1.9.0

Cédric Boutillier boutil at moszumanska.debian.org
Sun Dec 25 23:23:25 UTC 2016


This is an automated email from the git hooks/post-receive script.

boutil pushed a commit to branch master
in repository ruby-parallel.

commit 5b81806e62f13e4420ba0713c506c3261d7a39b6
Author: Cédric Boutillier <boutil at debian.org>
Date:   Sat Nov 19 01:35:13 2016 +0100

    New upstream version 1.9.0
---
 checksums.yaml.gz               | Bin 269 -> 0 bytes
 checksums.yaml.gz.sig           |   3 -
 data.tar.gz.sig                 |   2 -
 lib/parallel.rb                 | 477 +++++++++++++++++++++++-----------------
 lib/parallel/processor_count.rb |  85 +++++++
 lib/parallel/version.rb         |   2 +-
 metadata.gz.sig                 |   3 -
 metadata.yml                    |  67 ------
 parallel.gemspec                |  30 +++
 9 files changed, 387 insertions(+), 282 deletions(-)

diff --git a/checksums.yaml.gz b/checksums.yaml.gz
deleted file mode 100644
index 1bfb559..0000000
Binary files a/checksums.yaml.gz and /dev/null differ
diff --git a/checksums.yaml.gz.sig b/checksums.yaml.gz.sig
deleted file mode 100644
index 5599b67..0000000
--- a/checksums.yaml.gz.sig
+++ /dev/null
@@ -1,3 +0,0 @@
-&?SO�9J�Lu��m0J=����
��oy�&�ڛd �9ƀ*80(�olL�l=�L6:sjI[������P��a4�Y���*�eLh k
X�����x`7��S�|���^b�%Gr ������E�2�o

1�տ7�Y.�Q����
-�%[�M�Ux�s����d֦4�V�,�Ԗ�f�7�f	&t�ै��L�v��2r����;j�Y��ތڏSł<�ڧ
-
r�
"��C�K��h��-#E�K"�G��Q�
\ No newline at end of file
diff --git a/data.tar.gz.sig b/data.tar.gz.sig
deleted file mode 100644
index c81a90e..0000000
--- a/data.tar.gz.sig
+++ /dev/null
@@ -1,2 +0,0 @@
-!Ӆ�م�����>��d����
���ɤKZ
�*�-�s�^�w/�����R��M�������f��Wx�{�D�1�d>ii�)ٖ̆��
>i�mU[�:^:P�,k�m�h�a����S@�V
�3����(��s�x{����N:3zF�Y;��g
�Y��J҈.�
r���̗�0[n
�8��X��`m�k
��撑��tz�
�،瘝.�(@�g� ?���j���Kr*�z6�k�b�e����1p���PP��
-xR
\ No newline at end of file
diff --git a/lib/parallel.rb b/lib/parallel.rb
index ca309b1..e4a6425 100644
--- a/lib/parallel.rb
+++ b/lib/parallel.rb
@@ -1,14 +1,21 @@
-require 'thread' # to get Thread.exclusive
 require 'rbconfig'
 require 'parallel/version'
+require 'parallel/processor_count'
 
 module Parallel
-  class DeadWorker < Exception
+  extend Parallel::ProcessorCount
+
+  class DeadWorker < StandardError
+  end
+
+  class Break < StandardError
   end
 
-  class Break < Exception
+  class Kill < StandardError
   end
 
+  Stop = Object.new
+
   class ExceptionWrapper
     attr_reader :exception
     def initialize(exception)
@@ -23,52 +30,167 @@ module Parallel
 
   class Worker
     attr_reader :pid, :read, :write
+    attr_accessor :thread
     def initialize(read, write, pid)
       @read, @write, @pid = read, write, pid
     end
 
-    def close_pipes
-      read.close
-      write.close
+    def stop
+      close_pipes
+      wait # if it goes zombie, rather wait here to be able to debug
     end
 
-    def wait
-      Process.wait(pid)
-    rescue Interrupt
-      # process died
+    # might be passed to started_processes and simultaneously closed by another thread
+    # when running in isolation mode, so we have to check if it is closed before closing
+    def close_pipes
+      read.close unless read.closed?
+      write.close unless write.closed?
     end
 
-    def work(index)
+    def work(data)
       begin
-        Marshal.dump(index, write)
+        Marshal.dump(data, write)
       rescue Errno::EPIPE
         raise DeadWorker
       end
 
-      begin
+      result = begin
         Marshal.load(read)
       rescue EOFError
         raise DeadWorker
       end
+      raise result.exception if ExceptionWrapper === result
+      result
+    end
+
+    private
+
+    def wait
+      Process.wait(pid)
+    rescue Interrupt
+      # process died
     end
   end
 
-  class << self
-    def in_threads(options={:count => 2})
-      count, options = extract_count_from_options(options)
+  class JobFactory
+    def initialize(source, mutex)
+      @lambda = (source.respond_to?(:call) && source) || queue_wrapper(source)
+      @source = source.to_a unless @lambda # turn Range and other Enumerable-s into an Array
+      @mutex = mutex
+      @index = -1
+      @stopped = false
+    end
+
+    def next
+      if producer?
+        # - index and item stay in sync
+        # - do not call lambda after it has returned Stop
+        item, index = @mutex.synchronize do
+          return if @stopped
+          item = @lambda.call
+          @stopped = (item == Parallel::Stop)
+          return if @stopped
+          [item, @index += 1]
+        end
+      else
+        index = @mutex.synchronize { @index += 1 }
+        return if index >= size
+        item = @source[index]
+      end
+      [item, index]
+    end
+
+    def size
+      if producer?
+        Float::INFINITY
+      else
+        @source.size
+      end
+    end
+
+    # generate item that is sent to workers
+    # just index is faster + less likely to blow up with unserializable errors
+    def pack(item, index)
+      producer? ? [item, index] : index
+    end
+
+    # unpack item that is sent to workers
+    def unpack(data)
+      producer? ? data : [@source[data], data]
+    end
+
+    private
+
+    def producer?
+      @lambda
+    end
+
+    def queue_wrapper(array)
+      array.respond_to?(:num_waiting) && array.respond_to?(:pop) && lambda { array.pop(false) }
+    end
+  end
+
+  class UserInterruptHandler
+    INTERRUPT_SIGNAL = :SIGINT
 
-      out = []
-      threads = []
+    class << self
+      # kill all these pids or threads if user presses Ctrl+c
+      def kill_on_ctrl_c(pids, options)
+        @to_be_killed ||= []
+        old_interrupt = nil
+        signal = options.fetch(:interrupt_signal, INTERRUPT_SIGNAL)
 
-      count.times do |i|
-        threads[i] = Thread.new do
-          out[i] = yield(i)
+        if @to_be_killed.empty?
+          old_interrupt = trap_interrupt(signal) do
+            $stderr.puts 'Parallel execution interrupted, exiting ...'
+            @to_be_killed.flatten.each { |pid| kill(pid) }
+          end
+        end
+
+        @to_be_killed << pids
+
+        yield
+      ensure
+        @to_be_killed.pop # do not kill pids that could be used for new processes
+        restore_interrupt(old_interrupt, signal) if @to_be_killed.empty?
+      end
+
+      def kill(thing)
+        Process.kill(:KILL, thing)
+      rescue Errno::ESRCH
+        # some linux systems already automatically killed the children at this point
+        # so we just ignore them not being there
+      end
+
+      private
+
+      def trap_interrupt(signal)
+        old = Signal.trap signal, 'IGNORE'
+
+        Signal.trap signal do
+          yield
+          if old == "DEFAULT"
+            raise Interrupt
+          else
+            old.call
+          end
         end
+
+        old
       end
 
-      kill_on_ctrl_c(threads) { wait_for_threads(threads) }
+      def restore_interrupt(old, signal)
+        Signal.trap signal, old
+      end
+    end
+  end
 
-      out
+  class << self
+    def in_threads(options={:count => 2})
+      count, _ = extract_count_from_options(options)
+      Array.new(count).each_with_index.map do |_, i|
+        Thread.new { yield(i) }
+      end.map!(&:value)
     end
 
     def in_processes(options = {}, &block)
@@ -86,8 +208,8 @@ module Parallel
       each(array, options.merge(:with_index => true), &block)
     end
 
-    def map(array, options = {}, &block)
-      array = array.to_a # turn Range and other Enumerable-s into an Array
+    def map(source, options = {}, &block)
+      options[:mutex] = Mutex.new
 
       if RUBY_PLATFORM =~ /java/ and not options[:in_processes]
         method = :in_threads
@@ -100,18 +222,23 @@ module Parallel
         if Process.respond_to?(:fork)
           size = options[method] || processor_count
         else
-          $stderr.puts "Warning: Process.fork is not supported by this Ruby"
+          warn "Process.fork is not supported by this Ruby"
           size = 0
         end
       end
-      size = [array.size, size].min
+
+      job_factory = JobFactory.new(source, options[:mutex])
+      size = [job_factory.size, size].min
+
+      options[:return_results] = (options[:preserve_results] != false || !!options[:finish])
+      add_progress_bar!(job_factory, options)
 
       if size == 0
-        work_direct(array, options, &block)
+        work_direct(job_factory, options, &block)
       elsif method == :in_threads
-        work_in_threads(array, options.merge(:count => size), &block)
+        work_in_threads(job_factory, options.merge(:count => size), &block)
       else
-        work_in_processes(array, options.merge(:count => size), &block)
+        work_in_processes(job_factory, options.merge(:count => size), &block)
       end
     end
 
@@ -119,118 +246,73 @@ module Parallel
       map(array, options.merge(:with_index => true), &block)
     end
 
-    # Number of processors seen by the OS and used for process scheduling.
-    #
-    # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev
-    # * BSD: /sbin/sysctl
-    # * Cygwin: /proc/cpuinfo
-    # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl
-    # * HP-UX: /usr/sbin/ioscan
-    # * IRIX: /usr/sbin/sysconf
-    # * Linux: /proc/cpuinfo
-    # * Minix 3+: /proc/cpuinfo
-    # * Solaris: /usr/sbin/psrinfo
-    # * Tru64 UNIX: /usr/sbin/psrinfo
-    # * UnixWare: /usr/sbin/psrinfo
-    #
-    def processor_count
-      @processor_count ||= begin
-        os_name = RbConfig::CONFIG["target_os"]
-        if os_name =~ /mingw|mswin/
-          require 'win32ole'
-          result = WIN32OLE.connect("winmgmts://").ExecQuery(
-              "select NumberOfLogicalProcessors from Win32_Processor")
-          result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
-        elsif File.readable?("/proc/cpuinfo")
-          IO.read("/proc/cpuinfo").scan(/^processor/).size
-        elsif File.executable?("/usr/bin/hwprefs")
-          IO.popen("/usr/bin/hwprefs thread_count").read.to_i
-        elsif File.executable?("/usr/sbin/psrinfo")
-          IO.popen("/usr/sbin/psrinfo").read.scan(/^.*on-*line/).size
-        elsif File.executable?("/usr/sbin/ioscan")
-          IO.popen("/usr/sbin/ioscan -kC processor") do |out|
-            out.read.scan(/^.*processor/).size
-          end
-        elsif File.executable?("/usr/sbin/pmcycles")
-          IO.popen("/usr/sbin/pmcycles -m").read.count("\n")
-        elsif File.executable?("/usr/sbin/lsdev")
-          IO.popen("/usr/sbin/lsdev -Cc processor -S 1").read.count("\n")
-        elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
-          IO.popen("/usr/sbin/sysconf NPROC_ONLN").read.to_i
-        elsif File.executable?("/usr/sbin/sysctl")
-          IO.popen("/usr/sbin/sysctl -n hw.ncpu").read.to_i
-        elsif File.executable?("/sbin/sysctl")
-          IO.popen("/sbin/sysctl -n hw.ncpu").read.to_i
-        else
-          $stderr.puts "Unknown platform: " + RbConfig::CONFIG["target_os"]
-          $stderr.puts "Assuming 1 processor."
-          1
-        end
-      end
+    def worker_number
+      Thread.current[:parallel_worker_number]
     end
 
-    # Number of physical processor cores on the current system.
-    #
-    def physical_processor_count
-      @physical_processor_count ||= begin
-        ppc = case RbConfig::CONFIG["target_os"]
-        when /darwin1/
-          IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
-        when /linux/
-          cores = {}  # unique physical ID / core ID combinations
-          phy = 0
-          IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
-            if ln.start_with?("physical")
-              phy = ln[/\d+/]
-            elsif ln.start_with?("core")
-              cid = phy + ":" + ln[/\d+/]
-              cores[cid] = true if not cores[cid]
-            end
-          end
-          cores.count
-        when /mswin|mingw/
-          require 'win32ole'
-          result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
-              "select NumberOfCores from Win32_Processor")
-          result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
-        else
-          processor_count
-        end
-        # fall back to logical count if physical info is invalid
-        ppc > 0 ? ppc : processor_count
-      end
+    def worker_number=(worker_num)
+      Thread.current[:parallel_worker_number] = worker_num
     end
 
     private
 
-    def work_direct(array, options)
+    def add_progress_bar!(job_factory, options)
+      if progress_options = options[:progress]
+        raise "Progressbar can only be used with array like items" if job_factory.size == Float::INFINITY
+        require 'ruby-progressbar'
+
+        if progress_options == true
+          progress_options = { title: "Progress" }
+        elsif progress_options.respond_to? :to_str
+          progress_options = { title: progress_options.to_str }
+        end
+
+        progress_options = {
+          total: job_factory.size,
+          format: '%t |%E | %B | %a'
+        }.merge(progress_options)
+
+        progress = ProgressBar.create(progress_options)
+        old_finish = options[:finish]
+        options[:finish] = lambda do |item, i, result|
+          old_finish.call(item, i, result) if old_finish
+          progress.increment
+        end
+      end
+    end
+
+    def work_direct(job_factory, options, &block)
+      self.worker_number = 0
       results = []
-      array.each_with_index do |e,i|
-        results << (options[:with_index] ? yield(e,i) : yield(e))
+      while set = job_factory.next
+        item, index = set
+        results << with_instrumentation(item, index, options) do
+          call_with_index(item, index, options, &block)
+        end
       end
       results
+    ensure
+      self.worker_number = nil
     end
 
-    def work_in_threads(items, options, &block)
+    def work_in_threads(job_factory, options, &block)
+      raise "interrupt_signal is no longer supported for threads" if options[:interrupt_signal]
       results = []
-      current = -1
+      results_mutex = Mutex.new # arrays are not thread-safe on jRuby
       exception = nil
 
-      in_threads(options[:count]) do
-        # as long as there are more items, work on one of them
-        loop do
-          break if exception
-
-          index = Thread.exclusive{ current+=1 }
-          break if index >= items.size
-
-          with_instrumentation items[index], index, options do
-            begin
-              results[index] = call_with_index(items, index, options, &block)
-            rescue Exception => e
-              exception = e
-              break
+      in_threads(options) do |worker_num|
+        self.worker_number = worker_num
+        # as long as there are more jobs, work on one of them
+        while !exception && set = job_factory.next
+          begin
+            item, index = set
+            result = with_instrumentation item, index, options do
+              call_with_index(item, index, options, &block)
             end
+            results_mutex.synchronize { results[index] = result }
+          rescue StandardError => e
+            exception = e
           end
         end
       end
@@ -238,34 +320,49 @@ module Parallel
       handle_exception(exception, results)
     end
 
-    def work_in_processes(items, options, &blk)
-      workers = create_workers(items, options, &blk)
-      current_index = -1
+    def work_in_processes(job_factory, options, &blk)
+      workers = if options[:isolation]
+        [] # we create workers per job and not beforehand
+      else
+        create_workers(job_factory, options, &blk)
+      end
       results = []
+      results_mutex = Mutex.new # arrays are not thread-safe
       exception = nil
-      kill_on_ctrl_c(workers.map(&:pid)) do
-        in_threads(options[:count]) do |i|
+
+      UserInterruptHandler.kill_on_ctrl_c(workers.map(&:pid), options) do
+        in_threads(options) do |i|
           worker = workers[i]
 
           begin
             loop do
               break if exception
-              index = Thread.exclusive{ current_index += 1 }
-              break if index >= items.size
+              item, index = job_factory.next
+              break unless index
 
-              output = with_instrumentation items[index], index, options do
-                worker.work(index)
+              if options[:isolation]
+                worker = replace_worker(job_factory, workers, i, options, blk)
               end
 
-              if ExceptionWrapper === output
-                exception = output.exception
-              else
-                results[index] = output
+              worker.thread = Thread.current
+
+              begin
+                result = with_instrumentation item, index, options do
+                  worker.work(job_factory.pack(item, index))
+                end
+                results_mutex.synchronize { results[index] = result } # arrays are not threads safe on jRuby
+              rescue StandardError => e
+                exception = e
+                if Parallel::Kill === exception
+                  (workers - [worker]).each do |w|
+                    w.thread.kill
+                    UserInterruptHandler.kill(w.pid)
+                  end
+                end
               end
             end
           ensure
-            worker.close_pipes
-            worker.wait # if it goes zombie, rather wait here to be able to debug
+            worker.stop if worker
           end
         end
       end
@@ -273,29 +370,38 @@ module Parallel
       handle_exception(exception, results)
     end
 
-    def create_workers(items, options, &block)
+    def replace_worker(job_factory, workers, i, options, blk)
+      # old worker is no longer used ... stop it
+      worker = workers[i]
+      worker.stop if worker
+
+      # create a new replacement worker
+      running = workers - [worker]
+      workers[i] = worker(job_factory, options.merge(started_workers: running, worker_number: i), &blk)
+    end
+
+    def create_workers(job_factory, options, &block)
       workers = []
-      Array.new(options[:count]).each do
-        workers << worker(items, options.merge(:started_workers => workers), &block)
+      Array.new(options[:count]).each_with_index do |_, i|
+        workers << worker(job_factory, options.merge(started_workers: workers, worker_number: i), &block)
       end
       workers
     end
 
-    def worker(items, options, &block)
-      # use less memory on REE
-      GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
-
+    def worker(job_factory, options, &block)
       child_read, parent_write = IO.pipe
       parent_read, child_write = IO.pipe
 
       pid = Process.fork do
+        self.worker_number = options[:worker_number]
+
         begin
           options.delete(:started_workers).each(&:close_pipes)
 
           parent_write.close
           parent_read.close
 
-          process_incoming_jobs(child_read, child_write, items, options, &block)
+          process_incoming_jobs(child_read, child_write, job_factory, options, &block)
         ensure
           child_read.close
           child_write.close
@@ -308,30 +414,21 @@ module Parallel
       Worker.new(parent_read, parent_write, pid)
     end
 
-    def process_incoming_jobs(read, write, items, options, &block)
-      while !read.eof?
-        index = Marshal.load(read)
+    def process_incoming_jobs(read, write, job_factory, options, &block)
+      until read.eof?
+        data = Marshal.load(read)
+        item, index = job_factory.unpack(data)
         result = begin
-          call_with_index(items, index, options, &block)
-        rescue Exception => e
+          call_with_index(item, index, options, &block)
+        rescue StandardError => e
           ExceptionWrapper.new(e)
         end
         Marshal.dump(result, write)
       end
     end
 
-    def wait_for_threads(threads)
-      threads.compact.each do |t|
-        begin
-          t.join
-        rescue Interrupt
-          # thread died, do not stop other threads
-        end
-      end
-    end
-
     def handle_exception(exception, results)
-      return nil if exception.class == Parallel::Break
+      return nil if [Parallel::Break, Parallel::Kill].include? exception.class
       raise exception if exception
       results
     end
@@ -347,56 +444,24 @@ module Parallel
       [count, options]
     end
 
-    # kill all these pids or threads if user presses Ctrl+c
-    def kill_on_ctrl_c(things)
-      if defined?(@to_be_killed) && @to_be_killed
-        @to_be_killed << things
-      else
-        @to_be_killed = [things]
-        Signal.trap :SIGINT do
-          if @to_be_killed.any?
-            $stderr.puts 'Parallel execution interrupted, exiting ...'
-            @to_be_killed.flatten.compact.each { |thing| kill_that_thing!(thing) }
-          end
-          exit 1 # Quit with 'failed' signal
-        end
-      end
-      yield
-    ensure
-      @to_be_killed.pop # free threads for GC and do not kill pids that could be used for new processes
-    end
-
-    def kill_that_thing!(thing)
-      if thing.is_a?(Thread)
-        thing.kill
-      else
-        begin
-          Process.kill(:KILL, thing)
-        rescue Errno::ESRCH
-          # some linux systems already automatically killed the children at this point
-          # so we just ignore them not being there
-        end
-      end
-    end
-
-    def call_with_index(array, index, options, &block)
-      args = [array[index]]
+    def call_with_index(item, index, options, &block)
+      args = [item]
       args << index if options[:with_index]
-      if options[:preserve_results] == false
+      if options[:return_results]
         block.call(*args)
-        nil # avoid GC overhead of passing large results around
       else
         block.call(*args)
+        nil # avoid GC overhead of passing large results around
       end
     end
 
     def with_instrumentation(item, index, options)
       on_start = options[:start]
       on_finish = options[:finish]
-      on_start.call(item, index) if on_start
-      yield
-    ensure
-      on_finish.call(item, index) if on_finish
+      options[:mutex].synchronize { on_start.call(item, index) } if on_start
+      result = yield
+      options[:mutex].synchronize { on_finish.call(item, index, result) } if on_finish
+      result unless options[:preserve_results] == false
     end
   end
 end
diff --git a/lib/parallel/processor_count.rb b/lib/parallel/processor_count.rb
new file mode 100644
index 0000000..3c5a6f1
--- /dev/null
+++ b/lib/parallel/processor_count.rb
@@ -0,0 +1,85 @@
+module Parallel
+  module ProcessorCount
+    # Number of processors seen by the OS and used for process scheduling.
+    #
+    # * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev
+    # * BSD: /sbin/sysctl
+    # * Cygwin: /proc/cpuinfo
+    # * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl
+    # * HP-UX: /usr/sbin/ioscan
+    # * IRIX: /usr/sbin/sysconf
+    # * Linux: /proc/cpuinfo
+    # * Minix 3+: /proc/cpuinfo
+    # * Solaris: /usr/sbin/psrinfo
+    # * Tru64 UNIX: /usr/sbin/psrinfo
+    # * UnixWare: /usr/sbin/psrinfo
+    #
+    def processor_count
+      @processor_count ||= begin
+        os_name = RbConfig::CONFIG["target_os"]
+        if os_name =~ /mingw|mswin/
+          require 'win32ole'
+          result = WIN32OLE.connect("winmgmts://").ExecQuery(
+            "select NumberOfLogicalProcessors from Win32_Processor")
+          result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
+        elsif File.readable?("/proc/cpuinfo")
+          IO.read("/proc/cpuinfo").scan(/^processor/).size
+        elsif File.executable?("/usr/bin/hwprefs")
+          IO.popen("/usr/bin/hwprefs thread_count").read.to_i
+        elsif File.executable?("/usr/sbin/psrinfo")
+          IO.popen("/usr/sbin/psrinfo").read.scan(/^.*on-*line/).size
+        elsif File.executable?("/usr/sbin/ioscan")
+          IO.popen("/usr/sbin/ioscan -kC processor") do |out|
+            out.read.scan(/^.*processor/).size
+          end
+        elsif File.executable?("/usr/sbin/pmcycles")
+          IO.popen("/usr/sbin/pmcycles -m").read.count("\n")
+        elsif File.executable?("/usr/sbin/lsdev")
+          IO.popen("/usr/sbin/lsdev -Cc processor -S 1").read.count("\n")
+        elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
+          IO.popen("/usr/sbin/sysconf NPROC_ONLN").read.to_i
+        elsif File.executable?("/usr/sbin/sysctl")
+          IO.popen("/usr/sbin/sysctl -n hw.ncpu").read.to_i
+        elsif File.executable?("/sbin/sysctl")
+          IO.popen("/sbin/sysctl -n hw.ncpu").read.to_i
+        else
+          $stderr.puts "Unknown platform: " + RbConfig::CONFIG["target_os"]
+          $stderr.puts "Assuming 1 processor."
+          1
+        end
+      end
+    end
+
+    # Number of physical processor cores on the current system.
+    #
+    def physical_processor_count
+      @physical_processor_count ||= begin
+        ppc = case RbConfig::CONFIG["target_os"]
+        when /darwin1/
+          IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
+        when /linux/
+          cores = {}  # unique physical ID / core ID combinations
+          phy = 0
+          IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
+            if ln.start_with?("physical")
+              phy = ln[/\d+/]
+            elsif ln.start_with?("core")
+              cid = phy + ":" + ln[/\d+/]
+              cores[cid] = true if not cores[cid]
+            end
+          end
+          cores.count
+        when /mswin|mingw/
+          require 'win32ole'
+          result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
+            "select NumberOfCores from Win32_Processor")
+          result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
+        else
+          processor_count
+        end
+        # fall back to logical count if physical info is invalid
+        ppc > 0 ? ppc : processor_count
+      end
+    end
+  end
+end
diff --git a/lib/parallel/version.rb b/lib/parallel/version.rb
index 5159787..eb568a6 100644
--- a/lib/parallel/version.rb
+++ b/lib/parallel/version.rb
@@ -1,3 +1,3 @@
 module Parallel
-  VERSION = Version = '0.9.2'
+  VERSION = Version = '1.9.0'
 end
diff --git a/metadata.gz.sig b/metadata.gz.sig
deleted file mode 100644
index 8b8a670..0000000
--- a/metadata.gz.sig
+++ /dev/null
@@ -1,3 +0,0 @@
-U�P�´Z}�<�Pا6 &��3
��l�0�&S�
���0f,]c�wu򲼌��3�������\!�Bp�ÍB�uA�i���߃�M9^
�'2&e��hj<��j��!
����l�t�V�c�]���E�K^@���-��]�
U���vd̎
-%[���Y�mA�n0c)h/
-�7�r]bb��<K����&qpрh<����tmӦ>
�ƙ���t����[ϯ۔\�U�^f��/\م�,����*w
\ No newline at end of file
diff --git a/metadata.yml b/metadata.yml
deleted file mode 100644
index b40a693..0000000
--- a/metadata.yml
+++ /dev/null
@@ -1,67 +0,0 @@
---- !ruby/object:Gem::Specification
-name: parallel
-version: !ruby/object:Gem::Version
-  version: 0.9.2
-platform: ruby
-authors:
-- Michael Grosser
-autorequire: 
-bindir: bin
-cert_chain:
-- |
-  -----BEGIN CERTIFICATE-----
-  MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQUFADA/MRAwDgYDVQQDDAdtaWNo
-  YWVsMRcwFQYKCZImiZPyLGQBGRYHZ3Jvc3NlcjESMBAGCgmSJomT8ixkARkWAml0
-  MB4XDTEzMDIwMzE4MTMxMVoXDTE0MDIwMzE4MTMxMVowPzEQMA4GA1UEAwwHbWlj
-  aGFlbDEXMBUGCgmSJomT8ixkARkWB2dyb3NzZXIxEjAQBgoJkiaJk/IsZAEZFgJp
-  dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMorXo/hgbUq97+kII9H
-  MsQcLdC/7wQ1ZP2OshVHPkeP0qH8MBHGg6eYisOX2ubNagF9YTCZWnhrdKrwpLOO
-  cPLaZbjUjljJ3cQR3B8Yn1veV5IhG86QseTBjymzJWsLpqJ1UZGpfB9tXcsFtuxO
-  6vHvcIHdzvc/OUkICttLbH+1qb6rsHUceqh+JrH4GrsJ5H4hAfIdyS2XMK7YRKbh
-  h+IBu6dFWJJByzFsYmV1PDXln3UBmgAt65cmCu4qPfThioCGDzbSJrGDGLmw/pFX
-  FPpVCm1zgYSb1v6Qnf3cgXa2f2wYGm17+zAVyIDpwryFru9yF/jJxE38z/DRsd9R
-  /88CAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUsiNnXHtKeMYYcr4yJVmQ
-  WONL+IwwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQAlyN7kKo/NQCQ0
-  AOzZLZ3WAePvStkCFIJ53tsv5Kyo4pMAllv+BgPzzBt7qi605mFSL6zBd9uLou+W
-  Co3s48p1dy7CjjAfVQdmVNHF3MwXtfC2OEyvSQPi4xKR8iba8wa3xp9LVo1PuLpw
-  /6DsrChWw74HfsJN6qJOK684hJeT8lBYAUfiC3wD0owoPSg+XtyAAddisR+KV5Y1
-  NmVHuLtQcNTZy+gRht3ahJRMuC6QyLmkTsf+6MaenwAMkAgHdswGsJztOnNnBa3F
-  y0kCSWmK6D+x/SbfS6r7Ke07MRqziJdB9GuE1+0cIRuFh8EQ+LN6HXCKM5pon/GU
-  ycwMXfl0
-  -----END CERTIFICATE-----
-date: 2014-01-13 00:00:00.000000000 Z
-dependencies: []
-description: 
-email: michael at grosser.it
-executables: []
-extensions: []
-extra_rdoc_files: []
-files:
-- MIT-LICENSE.txt
-- lib/parallel.rb
-- lib/parallel/version.rb
-homepage: https://github.com/grosser/parallel
-licenses:
-- MIT
-metadata: {}
-post_install_message: 
-rdoc_options: []
-require_paths:
-- lib
-required_ruby_version: !ruby/object:Gem::Requirement
-  requirements:
-  - - '>='
-    - !ruby/object:Gem::Version
-      version: '0'
-required_rubygems_version: !ruby/object:Gem::Requirement
-  requirements:
-  - - '>='
-    - !ruby/object:Gem::Version
-      version: '0'
-requirements: []
-rubyforge_project: 
-rubygems_version: 2.0.14
-signing_key: 
-specification_version: 4
-summary: Run any kind of code in parallel processes
-test_files: []
diff --git a/parallel.gemspec b/parallel.gemspec
new file mode 100644
index 0000000..e6e67e4
--- /dev/null
+++ b/parallel.gemspec
@@ -0,0 +1,30 @@
+#########################################################
+# This file has been automatically generated by gem2tgz #
+#########################################################
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+  s.name = "parallel"
+  s.version = "1.9.0"
+
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+  s.authors = ["Michael Grosser"]
+  s.date = "2016-06-03"
+  s.email = "michael at grosser.it"
+  s.files = ["MIT-LICENSE.txt", "lib/parallel.rb", "lib/parallel/processor_count.rb", "lib/parallel/version.rb"]
+  s.homepage = "https://github.com/grosser/parallel"
+  s.licenses = ["MIT"]
+  s.require_paths = ["lib"]
+  s.required_ruby_version = Gem::Requirement.new(">= 1.9.3")
+  s.rubygems_version = "1.8.23"
+  s.summary = "Run any kind of code in parallel processes"
+
+  if s.respond_to? :specification_version then
+    s.specification_version = 4
+
+    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+    else
+    end
+  else
+  end
+end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-parallel.git



More information about the Pkg-ruby-extras-commits mailing list