parallel 1.17.0 → 1.21.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6b2d803fd3a136456287d19f88a5986742beed7246f587491992661235e43c2
4
- data.tar.gz: f3ed40c9c16f0a80e524f55c2f50d570d5da69c2f43ddc62023c323ddb968101
3
+ metadata.gz: 4dd167566b23262ceacbd640fda95c5e8d0d8149cc430f51ada53765a927cb18
4
+ data.tar.gz: 6a21c00b1109d5c665a471aec4a7af7d213ded2fc9123132b6576ee65ceb1758
5
5
  SHA512:
6
- metadata.gz: b5534907c40e98488528ed8c9bc08ae1eab61b5b8ec1ce9d1b02b40687d08a6f19f3721e962273674994654dbe7a55b8df05ff905342e0fb28ff810a6036d958
7
- data.tar.gz: d0b9f65e4a85636f8b464605b9b53de89ff529139801a5f8a8c7259783bce45eb1791c43218ba9ec3950e04e00a14f40b38c6079b52375d1c50f34a8db16c109
6
+ metadata.gz: 1f8a810c3b7fa77e8dd2b2539238b856b9b4ea40b5df49cf2cc4af2afbd2a73d9b6f34baab614c41e7b3b8bfe1917413bfbd014f647c5b4b96e7243d5433523d
7
+ data.tar.gz: 0bef1c7dc19b4738e228985512ee6cce1915f67ee29161b743821f69366d561ed8c3c5cbd4d9e6829342108fe9f10329563770d1978a660a04c58c0d9e2c8461
@@ -1,41 +1,42 @@
1
+ # frozen_string_literal: true
1
2
  require 'etc'
2
3
 
3
4
  module Parallel
5
+ # TODO: inline this method into parallel.rb and kill physical_processor_count in next major release
4
6
  module ProcessorCount
5
- # Number of processors seen by the OS and used for process scheduling. It's just wrapper for Etc.nprocessors
7
+ # Number of processors seen by the OS, used for process scheduling
6
8
  def processor_count
7
- @processor_count ||= begin
8
- Etc.nprocessors
9
- end
9
+ @processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || Etc.nprocessors)
10
10
  end
11
11
 
12
12
  # Number of physical processor cores on the current system.
13
- #
14
13
  def physical_processor_count
15
14
  @physical_processor_count ||= begin
16
- ppc = case RbConfig::CONFIG["target_os"]
17
- when /darwin1/
18
- IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
19
- when /linux/
20
- cores = {} # unique physical ID / core ID combinations
21
- phy = 0
22
- IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
23
- if ln.start_with?("physical")
24
- phy = ln[/\d+/]
25
- elsif ln.start_with?("core")
26
- cid = phy + ":" + ln[/\d+/]
27
- cores[cid] = true if not cores[cid]
15
+ ppc =
16
+ case RbConfig::CONFIG["target_os"]
17
+ when /darwin[12]/
18
+ IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
19
+ when /linux/
20
+ cores = {} # unique physical ID / core ID combinations
21
+ phy = 0
22
+ IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
23
+ if ln.start_with?("physical")
24
+ phy = ln[/\d+/]
25
+ elsif ln.start_with?("core")
26
+ cid = "#{phy}:#{ln[/\d+/]}"
27
+ cores[cid] = true unless cores[cid]
28
+ end
28
29
  end
30
+ cores.count
31
+ when /mswin|mingw/
32
+ require 'win32ole'
33
+ result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
34
+ "select NumberOfCores from Win32_Processor"
35
+ )
36
+ result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
37
+ else
38
+ processor_count
29
39
  end
30
- cores.count
31
- when /mswin|mingw/
32
- require 'win32ole'
33
- result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
34
- "select NumberOfCores from Win32_Processor")
35
- result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
36
- else
37
- processor_count
38
- end
39
40
  # fall back to logical count if physical info is invalid
40
41
  ppc > 0 ? ppc : processor_count
41
42
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Parallel
2
- VERSION = Version = '1.17.0'
3
+ VERSION = Version = '1.21.0' # rubocop:disable Naming/ConstantName
3
4
  end
data/lib/parallel.rb CHANGED
@@ -1,31 +1,40 @@
1
+ # frozen_string_literal: true
1
2
  require 'rbconfig'
2
3
  require 'parallel/version'
3
4
  require 'parallel/processor_count'
4
5
 
5
6
  module Parallel
6
- extend Parallel::ProcessorCount
7
+ extend ProcessorCount
8
+
9
+ Stop = Object.new.freeze
7
10
 
8
11
  class DeadWorker < StandardError
9
12
  end
10
13
 
11
14
  class Break < StandardError
15
+ attr_reader :value
16
+
17
+ def initialize(value = nil)
18
+ super()
19
+ @value = value
20
+ end
12
21
  end
13
22
 
14
- class Kill < StandardError
23
+ class Kill < Break
15
24
  end
16
25
 
17
26
  class UndumpableException < StandardError
18
27
  attr_reader :backtrace
28
+
19
29
  def initialize(original)
20
30
  super "#{original.class}: #{original.message}"
21
31
  @backtrace = original.backtrace
22
32
  end
23
33
  end
24
34
 
25
- Stop = Object.new.freeze
26
-
27
35
  class ExceptionWrapper
28
36
  attr_reader :exception
37
+
29
38
  def initialize(exception)
30
39
  # Remove the bindings stack added by the better_errors gem,
31
40
  # because it cannot be marshalled
@@ -36,7 +45,7 @@ module Parallel
36
45
  @exception =
37
46
  begin
38
47
  Marshal.dump(exception) && exception
39
- rescue
48
+ rescue StandardError
40
49
  UndumpableException.new(exception)
41
50
  end
42
51
  end
@@ -45,8 +54,11 @@ module Parallel
45
54
  class Worker
46
55
  attr_reader :pid, :read, :write
47
56
  attr_accessor :thread
57
+
48
58
  def initialize(read, write, pid)
49
- @read, @write, @pid = read, write, pid
59
+ @read = read
60
+ @write = write
61
+ @pid = pid
50
62
  end
51
63
 
52
64
  def stop
@@ -73,7 +85,7 @@ module Parallel
73
85
  rescue EOFError
74
86
  raise DeadWorker
75
87
  end
76
- raise result.exception if ExceptionWrapper === result
88
+ raise result.exception if result.is_a?(ExceptionWrapper)
77
89
  result
78
90
  end
79
91
 
@@ -102,7 +114,7 @@ module Parallel
102
114
  item, index = @mutex.synchronize do
103
115
  return if @stopped
104
116
  item = @lambda.call
105
- @stopped = (item == Parallel::Stop)
117
+ @stopped = (item == Stop)
106
118
  return if @stopped
107
119
  [item, @index += 1]
108
120
  end
@@ -140,7 +152,7 @@ module Parallel
140
152
  end
141
153
 
142
154
  def queue_wrapper(array)
143
- array.respond_to?(:num_waiting) && array.respond_to?(:pop) && lambda { array.pop(false) }
155
+ array.respond_to?(:num_waiting) && array.respond_to?(:pop) && -> { array.pop(false) }
144
156
  end
145
157
  end
146
158
 
@@ -156,7 +168,7 @@ module Parallel
156
168
 
157
169
  if @to_be_killed.empty?
158
170
  old_interrupt = trap_interrupt(signal) do
159
- $stderr.puts 'Parallel execution interrupted, exiting ...'
171
+ warn 'Parallel execution interrupted, exiting ...'
160
172
  @to_be_killed.flatten.each { |pid| kill(pid) }
161
173
  end
162
174
  end
@@ -200,45 +212,44 @@ module Parallel
200
212
  end
201
213
 
202
214
  class << self
203
- def in_threads(options={:count => 2})
215
+ def in_threads(options = { count: 2 })
216
+ threads = []
217
+ count, = extract_count_from_options(options)
218
+
204
219
  Thread.handle_interrupt(Exception => :never) do
205
- begin
206
- threads = []
207
- count, _ = extract_count_from_options(options)
220
+ Thread.handle_interrupt(Exception => :immediate) do
208
221
  count.times do |i|
209
222
  threads << Thread.new { yield(i) }
210
223
  end
211
- Thread.handle_interrupt(Exception => :immediate) do
212
- threads.map(&:value)
213
- end
214
- ensure
215
- threads.each(&:kill)
224
+ threads.map(&:value)
216
225
  end
226
+ ensure
227
+ threads.each(&:kill)
217
228
  end
218
229
  end
219
230
 
220
231
  def in_processes(options = {}, &block)
221
232
  count, options = extract_count_from_options(options)
222
233
  count ||= processor_count
223
- map(0...count, options.merge(:in_processes => count), &block)
234
+ map(0...count, options.merge(in_processes: count), &block)
224
235
  end
225
236
 
226
- def each(array, options={}, &block)
227
- map(array, options.merge(:preserve_results => false), &block)
237
+ def each(array, options = {}, &block)
238
+ map(array, options.merge(preserve_results: false), &block)
228
239
  end
229
240
 
230
241
  def any?(*args, &block)
231
242
  raise "You must provide a block when calling #any?" if block.nil?
232
- !each(*args) { |*a| raise Parallel::Kill if block.call(*a) }
243
+ !each(*args) { |*a| raise Kill if block.call(*a) }
233
244
  end
234
245
 
235
246
  def all?(*args, &block)
236
247
  raise "You must provide a block when calling #all?" if block.nil?
237
- !!each(*args) { |*a| raise Parallel::Kill unless block.call(*a) }
248
+ !!each(*args) { |*a| raise Kill unless block.call(*a) }
238
249
  end
239
250
 
240
- def each_with_index(array, options={}, &block)
241
- each(array, options.merge(:with_index => true), &block)
251
+ def each_with_index(array, options = {}, &block)
252
+ each(array, options.merge(with_index: true), &block)
242
253
  end
243
254
 
244
255
  def map(source, options = {}, &block)
@@ -246,8 +257,8 @@ module Parallel
246
257
  options[:mutex] = Mutex.new
247
258
 
248
259
  if options[:in_processes] && options[:in_threads]
249
- raise ArgumentError.new("Please specify only one of `in_processes` or `in_threads`.")
250
- elsif RUBY_PLATFORM =~ /java/ and not options[:in_processes]
260
+ raise ArgumentError, "Please specify only one of `in_processes` or `in_threads`."
261
+ elsif RUBY_PLATFORM =~ (/java/) && !(options[:in_processes])
251
262
  method = :in_threads
252
263
  size = options[method] || processor_count
253
264
  elsif options[:in_threads]
@@ -269,20 +280,22 @@ module Parallel
269
280
  options[:return_results] = (options[:preserve_results] != false || !!options[:finish])
270
281
  add_progress_bar!(job_factory, options)
271
282
 
272
- results = if size == 0
273
- work_direct(job_factory, options, &block)
274
- elsif method == :in_threads
275
- work_in_threads(job_factory, options.merge(:count => size), &block)
276
- else
277
- work_in_processes(job_factory, options.merge(:count => size), &block)
278
- end
279
- if results
280
- options[:return_results] ? results : source
281
- end
283
+ result =
284
+ if size == 0
285
+ work_direct(job_factory, options, &block)
286
+ elsif method == :in_threads
287
+ work_in_threads(job_factory, options.merge(count: size), &block)
288
+ else
289
+ work_in_processes(job_factory, options.merge(count: size), &block)
290
+ end
291
+
292
+ return result.value if result.is_a?(Break)
293
+ raise result if result.is_a?(Exception)
294
+ options[:return_results] ? result : source
282
295
  end
283
296
 
284
- def map_with_index(array, options={}, &block)
285
- map(array, options.merge(:with_index => true), &block)
297
+ def map_with_index(array, options = {}, &block)
298
+ map(array, options.merge(with_index: true), &block)
286
299
  end
287
300
 
288
301
  def flat_map(*args, &block)
@@ -336,10 +349,10 @@ module Parallel
336
349
  call_with_index(item, index, options, &block)
337
350
  end
338
351
  end
339
- rescue
352
+ rescue StandardError
340
353
  exception = $!
341
354
  end
342
- handle_exception(exception, results)
355
+ exception || results
343
356
  ensure
344
357
  self.worker_number = nil
345
358
  end
@@ -360,13 +373,13 @@ module Parallel
360
373
  call_with_index(item, index, options, &block)
361
374
  end
362
375
  results_mutex.synchronize { results[index] = result }
363
- rescue
376
+ rescue StandardError
364
377
  exception = $!
365
378
  end
366
379
  end
367
380
  end
368
381
 
369
- handle_exception(exception, results)
382
+ exception || results
370
383
  end
371
384
 
372
385
  def work_in_processes(job_factory, options, &blk)
@@ -400,9 +413,9 @@ module Parallel
400
413
  results_mutex.synchronize { results[index] = result } # arrays are not threads safe on jRuby
401
414
  rescue StandardError => e
402
415
  exception = e
403
- if Parallel::Kill === exception
416
+ if exception.is_a?(Kill)
404
417
  (workers - [worker]).each do |w|
405
- w.thread.kill if w.thread
418
+ w.thread&.kill
406
419
  UserInterruptHandler.kill(w.pid)
407
420
  end
408
421
  end
@@ -413,19 +426,18 @@ module Parallel
413
426
  end
414
427
  end
415
428
  end
416
-
417
- handle_exception(exception, results)
429
+ exception || results
418
430
  end
419
431
 
420
- def replace_worker(job_factory, workers, i, options, blk)
432
+ def replace_worker(job_factory, workers, index, options, blk)
421
433
  options[:mutex].synchronize do
422
434
  # old worker is no longer used ... stop it
423
- worker = workers[i]
435
+ worker = workers[index]
424
436
  worker.stop
425
437
 
426
438
  # create a new replacement worker
427
439
  running = workers - [worker]
428
- workers[i] = worker(job_factory, options.merge(started_workers: running, worker_number: i), &blk)
440
+ workers[index] = worker(job_factory, options.merge(started_workers: running, worker_number: index), &blk)
429
441
  end
430
442
  end
431
443
 
@@ -467,11 +479,17 @@ module Parallel
467
479
  until read.eof?
468
480
  data = Marshal.load(read)
469
481
  item, index = job_factory.unpack(data)
470
- result = begin
471
- call_with_index(item, index, options, &block)
472
- rescue
473
- ExceptionWrapper.new($!)
474
- end
482
+
483
+ result =
484
+ begin
485
+ call_with_index(item, index, options, &block)
486
+ # https://github.com/rspec/rspec-support/blob/673133cdd13b17077b3d88ece8d7380821f8d7dc/lib/rspec/support.rb#L132-L140
487
+ rescue NoMemoryError, SignalException, Interrupt, SystemExit # rubocop:disable Lint/ShadowedException
488
+ raise $!
489
+ rescue Exception # # rubocop:disable Lint/RescueException
490
+ ExceptionWrapper.new($!)
491
+ end
492
+
475
493
  begin
476
494
  Marshal.dump(result, write)
477
495
  rescue Errno::EPIPE
@@ -480,12 +498,6 @@ module Parallel
480
498
  end
481
499
  end
482
500
 
483
- def handle_exception(exception, results)
484
- return nil if [Parallel::Break, Parallel::Kill].include? exception.class
485
- raise exception if exception
486
- results
487
- end
488
-
489
501
  # options is either a Integer or a Hash with :count
490
502
  def extract_count_from_options(options)
491
503
  if options.is_a?(Hash)
@@ -500,10 +512,10 @@ module Parallel
500
512
  def call_with_index(item, index, options, &block)
501
513
  args = [item]
502
514
  args << index if options[:with_index]
515
+ results = block.call(*args)
503
516
  if options[:return_results]
504
- block.call(*args)
517
+ results
505
518
  else
506
- block.call(*args)
507
519
  nil # avoid GC overhead of passing large results around
508
520
  end
509
521
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-01 00:00:00.000000000 Z
11
+ date: 2021-09-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: michael@grosser.it
@@ -23,7 +23,11 @@ files:
23
23
  homepage: https://github.com/grosser/parallel
24
24
  licenses:
25
25
  - MIT
26
- metadata: {}
26
+ metadata:
27
+ bug_tracker_uri: https://github.com/grosser/parallel/issues
28
+ documentation_uri: https://github.com/grosser/parallel/blob/v1.21.0/Readme.md
29
+ source_code_uri: https://github.com/grosser/parallel/tree/v1.21.0
30
+ wiki_uri: https://github.com/grosser/parallel/wiki
27
31
  post_install_message:
28
32
  rdoc_options: []
29
33
  require_paths:
@@ -32,15 +36,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
32
36
  requirements:
33
37
  - - ">="
34
38
  - !ruby/object:Gem::Version
35
- version: '2.2'
39
+ version: '2.5'
36
40
  required_rubygems_version: !ruby/object:Gem::Requirement
37
41
  requirements:
38
42
  - - ">="
39
43
  - !ruby/object:Gem::Version
40
44
  version: '0'
41
45
  requirements: []
42
- rubyforge_project:
43
- rubygems_version: 2.7.6
46
+ rubygems_version: 3.2.16
44
47
  signing_key:
45
48
  specification_version: 4
46
49
  summary: Run any kind of code in parallel processes