parallel 1.23.0 → 1.26.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/parallel/version.rb +1 -1
  3. data/lib/parallel.rb +76 -20
  4. metadata +10 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b8bb887652e89a339de17f31e8482aec8664426b2b12eb11566779f53153a56
4
- data.tar.gz: e5fa1401f5748de7216a6d973d1ca1a2af514caeaec1dacafb153d2a5538334d
3
+ metadata.gz: 404f38d083ffa4ed2163c3018f5243fe487b6154905afa83b59320380bd3629a
4
+ data.tar.gz: 832f558729b425fa3e2ad6b9a3d6418c44d0f4a2ecc180a398a28b2301cd5cab
5
5
  SHA512:
6
- metadata.gz: 481a4b04da349a2eb88cdcab724dc3c47efe757dcb61889a3105d0097fb3255ff6283470f6c2bc636c1bd053e274516fddfa33f8d362e8208f6f57638864ca48
7
- data.tar.gz: 9093769c22e258cb921c1ab6ead1c7083fcc1d315b7bc268dff807c0fe1c4468b4316171e5f837283d7387ecdb01284f55763b60912c4bce7548aa9c869cc57b
6
+ metadata.gz: 5947502dc01d242a8a1cef0e2133cc3df913107941f5ba5bd82032bda76de6358bc44e62848909a75f2bfa45c867ee099f454c2652555265d734a166c988d144
7
+ data.tar.gz: '08f69f6c82041f015dee319ccc42bb0b1e20fc3d58b4e4007c1636ce459a71b0625ebb3ec8c28549562c1ed3f99f4182da41d8741a42eeeb4a96cb51b9bff701'
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Parallel
3
- VERSION = Version = '1.23.0' # rubocop:disable Naming/ConstantName
3
+ VERSION = Version = '1.26.3' # rubocop:disable Naming/ConstantName
4
4
  end
data/lib/parallel.rb CHANGED
@@ -24,7 +24,7 @@ module Parallel
24
24
  attr_reader :backtrace
25
25
 
26
26
  def initialize(original)
27
- super "#{original.class}: #{original.message}"
27
+ super("#{original.class}: #{original.message}")
28
28
  @backtrace = original.backtrace
29
29
  end
30
30
  end
@@ -300,12 +300,12 @@ module Parallel
300
300
  map(array, options.merge(with_index: true), &block)
301
301
  end
302
302
 
303
- def flat_map(*args, &block)
304
- map(*args, &block).flatten(1)
303
+ def flat_map(...)
304
+ map(...).flatten(1)
305
305
  end
306
306
 
307
- def filter_map(*args, &block)
308
- map(*args, &block).compact
307
+ def filter_map(...)
308
+ map(...).compact
309
309
  end
310
310
 
311
311
  # Number of physical processor cores on the current system.
@@ -328,11 +328,7 @@ module Parallel
328
328
  end
329
329
  cores.count
330
330
  when /mswin|mingw/
331
- require 'win32ole'
332
- result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
333
- "select NumberOfCores from Win32_Processor"
334
- )
335
- result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
331
+ physical_processor_count_windows
336
332
  else
337
333
  processor_count
338
334
  end
@@ -341,10 +337,10 @@ module Parallel
341
337
  end
342
338
  end
343
339
 
344
- # Number of processors seen by the OS, used for process scheduling
340
+ # Number of processors seen by the OS or value considering CPU quota if the process is inside a cgroup,
341
+ # used for process scheduling
345
342
  def processor_count
346
- require 'etc'
347
- @processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || Etc.nprocessors)
343
+ @processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || available_processor_count)
348
344
  end
349
345
 
350
346
  def worker_number
@@ -358,8 +354,35 @@ module Parallel
358
354
 
359
355
  private
360
356
 
357
+ def physical_processor_count_windows
358
+ # Get-CimInstance introduced in PowerShell 3 or earlier: https://learn.microsoft.com/en-us/previous-versions/powershell/module/cimcmdlets/get-ciminstance?view=powershell-3.0
359
+ result = run(
360
+ 'powershell -command "Get-CimInstance -ClassName Win32_Processor -Property NumberOfCores ' \
361
+ '| Select-Object -Property NumberOfCores"'
362
+ )
363
+ if !result || $?.exitstatus != 0
364
+ # fallback to deprecated wmic for older systems
365
+ result = run("wmic cpu get NumberOfCores")
366
+ end
367
+ if !result || $?.exitstatus != 0
368
+ # Bail out if both commands returned something unexpected
369
+ warn "guessing pyhsical processor count"
370
+ processor_count
371
+ else
372
+ # powershell: "\nNumberOfCores\n-------------\n 4\n\n\n"
373
+ # wmic: "NumberOfCores \n\n4 \n\n\n\n"
374
+ result.scan(/\d+/).map(&:to_i).reduce(:+)
375
+ end
376
+ end
377
+
378
+ def run(command)
379
+ IO.popen(command, &:read)
380
+ rescue Errno::ENOENT
381
+ # Ignore
382
+ end
383
+
361
384
  def add_progress_bar!(job_factory, options)
362
- if progress_options = options[:progress]
385
+ if (progress_options = options[:progress])
363
386
  raise "Progressbar can only be used with array like items" if job_factory.size == Float::INFINITY
364
387
  require 'ruby-progressbar'
365
388
 
@@ -388,7 +411,7 @@ module Parallel
388
411
  results = []
389
412
  exception = nil
390
413
  begin
391
- while set = job_factory.next
414
+ while (set = job_factory.next)
392
415
  item, index = set
393
416
  results << with_instrumentation(item, index, options) do
394
417
  call_with_index(item, index, options, &block)
@@ -411,7 +434,7 @@ module Parallel
411
434
  in_threads(options) do |worker_num|
412
435
  self.worker_number = worker_num
413
436
  # as long as there are more jobs, work on one of them
414
- while !exception && set = job_factory.next
437
+ while !exception && (set = job_factory.next)
415
438
  begin
416
439
  item, index = set
417
440
  result = with_instrumentation item, index, options do
@@ -455,7 +478,7 @@ module Parallel
455
478
 
456
479
  # start
457
480
  ractors.dup.each do |ractor|
458
- if set = job_factory.next
481
+ if (set = job_factory.next)
459
482
  item, index = set
460
483
  instrument_start item, index, options
461
484
  ractor.send [callback, item, index]
@@ -466,7 +489,7 @@ module Parallel
466
489
  end
467
490
 
468
491
  # replace with new items
469
- while set = job_factory.next
492
+ while (set = job_factory.next)
470
493
  item_next, index_next = set
471
494
  done, (exception, result, item, index) = Ractor.select(*ractors)
472
495
  if exception
@@ -640,13 +663,46 @@ module Parallel
640
663
  end
641
664
 
642
665
  def instrument_finish(item, index, result, options)
643
- return unless on_finish = options[:finish]
666
+ return unless (on_finish = options[:finish])
667
+ return instrument_finish_in_order(item, index, result, options) if options[:finish_in_order]
644
668
  options[:mutex].synchronize { on_finish.call(item, index, result) }
645
669
  end
646
670
 
671
+ # yield results in the order of the input items
672
+ # needs to use `options` to store state between executions
673
+ # needs to use `done` index since a nil result would also be valid
674
+ def instrument_finish_in_order(item, index, result, options)
675
+ options[:mutex].synchronize do
676
+ # initialize our state
677
+ options[:finish_done] ||= []
678
+ options[:finish_expecting] ||= 0 # we wait for item at index 0
679
+
680
+ # store current result
681
+ options[:finish_done][index] = [item, result]
682
+
683
+ # yield all results that are now in order
684
+ break unless index == options[:finish_expecting]
685
+ index.upto(options[:finish_done].size).each do |i|
686
+ break unless (done = options[:finish_done][i])
687
+ options[:finish_done][i] = nil # allow GC to free this item and result
688
+ options[:finish].call(done[0], i, done[1])
689
+ options[:finish_expecting] += 1
690
+ end
691
+ end
692
+ end
693
+
647
694
  def instrument_start(item, index, options)
648
- return unless on_start = options[:start]
695
+ return unless (on_start = options[:start])
649
696
  options[:mutex].synchronize { on_start.call(item, index) }
650
697
  end
698
+
699
+ def available_processor_count
700
+ gem 'concurrent-ruby', '>= 1.3.4'
701
+ require 'concurrent-ruby'
702
+ Concurrent.available_processor_count.floor
703
+ rescue LoadError
704
+ require 'etc'
705
+ Etc.nprocessors
706
+ end
651
707
  end
652
708
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.23.0
4
+ version: 1.26.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-18 00:00:00.000000000 Z
11
+ date: 2024-08-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description:
13
+ description:
14
14
  email: michael@grosser.it
15
15
  executables: []
16
16
  extensions: []
@@ -24,10 +24,10 @@ licenses:
24
24
  - MIT
25
25
  metadata:
26
26
  bug_tracker_uri: https://github.com/grosser/parallel/issues
27
- documentation_uri: https://github.com/grosser/parallel/blob/v1.23.0/Readme.md
28
- source_code_uri: https://github.com/grosser/parallel/tree/v1.23.0
27
+ documentation_uri: https://github.com/grosser/parallel/blob/v1.26.3/Readme.md
28
+ source_code_uri: https://github.com/grosser/parallel/tree/v1.26.3
29
29
  wiki_uri: https://github.com/grosser/parallel/wiki
30
- post_install_message:
30
+ post_install_message:
31
31
  rdoc_options: []
32
32
  require_paths:
33
33
  - lib
@@ -35,15 +35,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
35
35
  requirements:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
- version: '2.5'
38
+ version: '2.7'
39
39
  required_rubygems_version: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
43
  version: '0'
44
44
  requirements: []
45
- rubygems_version: 3.1.6
46
- signing_key:
45
+ rubygems_version: 3.4.10
46
+ signing_key:
47
47
  specification_version: 4
48
48
  summary: Run any kind of code in parallel processes
49
49
  test_files: []