parallel 1.20.0 → 1.27.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 +4 -4
- data/lib/parallel/version.rb +2 -1
- data/lib/parallel.rb +241 -56
- metadata +6 -11
- data/lib/parallel/processor_count.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a657608c1d396b6c563f8905778d64d24c4ae6bb010e716e60a45ccc4a71295e
|
4
|
+
data.tar.gz: eb26d89f92521fed38f1bdf99f6374a2cca2e3f4c1557a7f3f92ed81d396ffb7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7accf7f9b3d74e1e76f7b89db8f9040d23876e8373a6d6fa9b31e927b9ca4ce8b13330ffd888871795c79d6e3bbe7b17aa787789146ffed67f46c21fa9af3ad
|
7
|
+
data.tar.gz: ead77e379ad1c18641ca8d0457214af393beeee60fe4e5558c69d601f6f269628ce2830b6a35a7fe66e461b88fbebad33dd9bb8b767324030294e2a8f7164d8d
|
data/lib/parallel/version.rb
CHANGED
data/lib/parallel.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'rbconfig'
|
2
3
|
require 'parallel/version'
|
3
|
-
require 'parallel/processor_count'
|
4
4
|
|
5
5
|
module Parallel
|
6
|
-
extend ProcessorCount
|
7
|
-
|
8
6
|
Stop = Object.new.freeze
|
9
7
|
|
10
8
|
class DeadWorker < StandardError
|
@@ -12,7 +10,9 @@ module Parallel
|
|
12
10
|
|
13
11
|
class Break < StandardError
|
14
12
|
attr_reader :value
|
13
|
+
|
15
14
|
def initialize(value = nil)
|
15
|
+
super()
|
16
16
|
@value = value
|
17
17
|
end
|
18
18
|
end
|
@@ -22,14 +22,16 @@ module Parallel
|
|
22
22
|
|
23
23
|
class UndumpableException < StandardError
|
24
24
|
attr_reader :backtrace
|
25
|
+
|
25
26
|
def initialize(original)
|
26
|
-
super
|
27
|
+
super("#{original.class}: #{original.message}")
|
27
28
|
@backtrace = original.backtrace
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
32
|
class ExceptionWrapper
|
32
33
|
attr_reader :exception
|
34
|
+
|
33
35
|
def initialize(exception)
|
34
36
|
# Remove the bindings stack added by the better_errors gem,
|
35
37
|
# because it cannot be marshalled
|
@@ -40,7 +42,7 @@ module Parallel
|
|
40
42
|
@exception =
|
41
43
|
begin
|
42
44
|
Marshal.dump(exception) && exception
|
43
|
-
rescue
|
45
|
+
rescue StandardError
|
44
46
|
UndumpableException.new(exception)
|
45
47
|
end
|
46
48
|
end
|
@@ -49,8 +51,11 @@ module Parallel
|
|
49
51
|
class Worker
|
50
52
|
attr_reader :pid, :read, :write
|
51
53
|
attr_accessor :thread
|
54
|
+
|
52
55
|
def initialize(read, write, pid)
|
53
|
-
@read
|
56
|
+
@read = read
|
57
|
+
@write = write
|
58
|
+
@pid = pid
|
54
59
|
end
|
55
60
|
|
56
61
|
def stop
|
@@ -77,7 +82,7 @@ module Parallel
|
|
77
82
|
rescue EOFError
|
78
83
|
raise DeadWorker
|
79
84
|
end
|
80
|
-
raise result.exception if ExceptionWrapper
|
85
|
+
raise result.exception if result.is_a?(ExceptionWrapper)
|
81
86
|
result
|
82
87
|
end
|
83
88
|
|
@@ -144,7 +149,7 @@ module Parallel
|
|
144
149
|
end
|
145
150
|
|
146
151
|
def queue_wrapper(array)
|
147
|
-
array.respond_to?(:num_waiting) && array.respond_to?(:pop) &&
|
152
|
+
array.respond_to?(:num_waiting) && array.respond_to?(:pop) && -> { array.pop(false) }
|
148
153
|
end
|
149
154
|
end
|
150
155
|
|
@@ -160,7 +165,7 @@ module Parallel
|
|
160
165
|
|
161
166
|
if @to_be_killed.empty?
|
162
167
|
old_interrupt = trap_interrupt(signal) do
|
163
|
-
|
168
|
+
warn 'Parallel execution interrupted, exiting ...'
|
164
169
|
@to_be_killed.flatten.each { |pid| kill(pid) }
|
165
170
|
end
|
166
171
|
end
|
@@ -204,32 +209,30 @@ module Parallel
|
|
204
209
|
end
|
205
210
|
|
206
211
|
class << self
|
207
|
-
def in_threads(options={:
|
212
|
+
def in_threads(options = { count: 2 })
|
208
213
|
threads = []
|
209
|
-
count,
|
214
|
+
count, = extract_count_from_options(options)
|
210
215
|
|
211
216
|
Thread.handle_interrupt(Exception => :never) do
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
threads << Thread.new { yield(i) }
|
216
|
-
end
|
217
|
-
threads.map(&:value)
|
217
|
+
Thread.handle_interrupt(Exception => :immediate) do
|
218
|
+
count.times do |i|
|
219
|
+
threads << Thread.new { yield(i) }
|
218
220
|
end
|
219
|
-
|
220
|
-
threads.each(&:kill)
|
221
|
+
threads.map(&:value)
|
221
222
|
end
|
223
|
+
ensure
|
224
|
+
threads.each(&:kill)
|
222
225
|
end
|
223
226
|
end
|
224
227
|
|
225
228
|
def in_processes(options = {}, &block)
|
226
229
|
count, options = extract_count_from_options(options)
|
227
230
|
count ||= processor_count
|
228
|
-
map(0...count, options.merge(:
|
231
|
+
map(0...count, options.merge(in_processes: count), &block)
|
229
232
|
end
|
230
233
|
|
231
|
-
def each(array, options={}, &block)
|
232
|
-
map(array, options.merge(:
|
234
|
+
def each(array, options = {}, &block)
|
235
|
+
map(array, options.merge(preserve_results: false), &block)
|
233
236
|
end
|
234
237
|
|
235
238
|
def any?(*args, &block)
|
@@ -242,8 +245,8 @@ module Parallel
|
|
242
245
|
!!each(*args) { |*a| raise Kill unless block.call(*a) }
|
243
246
|
end
|
244
247
|
|
245
|
-
def each_with_index(array, options={}, &block)
|
246
|
-
each(array, options.merge(:
|
248
|
+
def each_with_index(array, options = {}, &block)
|
249
|
+
each(array, options.merge(with_index: true), &block)
|
247
250
|
end
|
248
251
|
|
249
252
|
def map(source, options = {}, &block)
|
@@ -251,13 +254,16 @@ module Parallel
|
|
251
254
|
options[:mutex] = Mutex.new
|
252
255
|
|
253
256
|
if options[:in_processes] && options[:in_threads]
|
254
|
-
raise ArgumentError
|
255
|
-
elsif RUBY_PLATFORM =~ /java/
|
257
|
+
raise ArgumentError, "Please specify only one of `in_processes` or `in_threads`."
|
258
|
+
elsif RUBY_PLATFORM =~ (/java/) && !options[:in_processes]
|
256
259
|
method = :in_threads
|
257
260
|
size = options[method] || processor_count
|
258
261
|
elsif options[:in_threads]
|
259
262
|
method = :in_threads
|
260
263
|
size = options[method]
|
264
|
+
elsif options[:in_ractors]
|
265
|
+
method = :in_ractors
|
266
|
+
size = options[method]
|
261
267
|
else
|
262
268
|
method = :in_processes
|
263
269
|
if Process.respond_to?(:fork)
|
@@ -278,9 +284,11 @@ module Parallel
|
|
278
284
|
if size == 0
|
279
285
|
work_direct(job_factory, options, &block)
|
280
286
|
elsif method == :in_threads
|
281
|
-
work_in_threads(job_factory, options.merge(:
|
287
|
+
work_in_threads(job_factory, options.merge(count: size), &block)
|
288
|
+
elsif method == :in_ractors
|
289
|
+
work_in_ractors(job_factory, options.merge(count: size), &block)
|
282
290
|
else
|
283
|
-
work_in_processes(job_factory, options.merge(:
|
291
|
+
work_in_processes(job_factory, options.merge(count: size), &block)
|
284
292
|
end
|
285
293
|
|
286
294
|
return result.value if result.is_a?(Break)
|
@@ -288,12 +296,51 @@ module Parallel
|
|
288
296
|
options[:return_results] ? result : source
|
289
297
|
end
|
290
298
|
|
291
|
-
def map_with_index(array, options={}, &block)
|
292
|
-
map(array, options.merge(:
|
299
|
+
def map_with_index(array, options = {}, &block)
|
300
|
+
map(array, options.merge(with_index: true), &block)
|
301
|
+
end
|
302
|
+
|
303
|
+
def flat_map(...)
|
304
|
+
map(...).flatten(1)
|
305
|
+
end
|
306
|
+
|
307
|
+
def filter_map(...)
|
308
|
+
map(...).compact
|
309
|
+
end
|
310
|
+
|
311
|
+
# Number of physical processor cores on the current system.
|
312
|
+
def physical_processor_count
|
313
|
+
@physical_processor_count ||= begin
|
314
|
+
ppc =
|
315
|
+
case RbConfig::CONFIG["target_os"]
|
316
|
+
when /darwin[12]/
|
317
|
+
IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
|
318
|
+
when /linux/
|
319
|
+
cores = {} # unique physical ID / core ID combinations
|
320
|
+
phy = 0
|
321
|
+
File.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
|
322
|
+
if ln.start_with?("physical")
|
323
|
+
phy = ln[/\d+/]
|
324
|
+
elsif ln.start_with?("core")
|
325
|
+
cid = "#{phy}:#{ln[/\d+/]}"
|
326
|
+
cores[cid] = true unless cores[cid]
|
327
|
+
end
|
328
|
+
end
|
329
|
+
cores.count
|
330
|
+
when /mswin|mingw/
|
331
|
+
physical_processor_count_windows
|
332
|
+
else
|
333
|
+
processor_count
|
334
|
+
end
|
335
|
+
# fall back to logical count if physical info is invalid
|
336
|
+
ppc > 0 ? ppc : processor_count
|
337
|
+
end
|
293
338
|
end
|
294
339
|
|
295
|
-
|
296
|
-
|
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
|
342
|
+
def processor_count
|
343
|
+
@processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || available_processor_count)
|
297
344
|
end
|
298
345
|
|
299
346
|
def worker_number
|
@@ -307,8 +354,35 @@ module Parallel
|
|
307
354
|
|
308
355
|
private
|
309
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
|
+
|
310
384
|
def add_progress_bar!(job_factory, options)
|
311
|
-
if progress_options = options[:progress]
|
385
|
+
if (progress_options = options[:progress])
|
312
386
|
raise "Progressbar can only be used with array like items" if job_factory.size == Float::INFINITY
|
313
387
|
require 'ruby-progressbar'
|
314
388
|
|
@@ -337,13 +411,13 @@ module Parallel
|
|
337
411
|
results = []
|
338
412
|
exception = nil
|
339
413
|
begin
|
340
|
-
while set = job_factory.next
|
414
|
+
while (set = job_factory.next)
|
341
415
|
item, index = set
|
342
416
|
results << with_instrumentation(item, index, options) do
|
343
417
|
call_with_index(item, index, options, &block)
|
344
418
|
end
|
345
419
|
end
|
346
|
-
rescue
|
420
|
+
rescue StandardError
|
347
421
|
exception = $!
|
348
422
|
end
|
349
423
|
exception || results
|
@@ -360,14 +434,14 @@ module Parallel
|
|
360
434
|
in_threads(options) do |worker_num|
|
361
435
|
self.worker_number = worker_num
|
362
436
|
# as long as there are more jobs, work on one of them
|
363
|
-
while !exception && set = job_factory.next
|
437
|
+
while !exception && (set = job_factory.next)
|
364
438
|
begin
|
365
439
|
item, index = set
|
366
440
|
result = with_instrumentation item, index, options do
|
367
441
|
call_with_index(item, index, options, &block)
|
368
442
|
end
|
369
443
|
results_mutex.synchronize { results[index] = result }
|
370
|
-
rescue
|
444
|
+
rescue StandardError
|
371
445
|
exception = $!
|
372
446
|
end
|
373
447
|
end
|
@@ -376,6 +450,72 @@ module Parallel
|
|
376
450
|
exception || results
|
377
451
|
end
|
378
452
|
|
453
|
+
def work_in_ractors(job_factory, options)
|
454
|
+
exception = nil
|
455
|
+
results = []
|
456
|
+
results_mutex = Mutex.new # arrays are not thread-safe on jRuby
|
457
|
+
|
458
|
+
callback = options[:ractor]
|
459
|
+
if block_given? || !callback
|
460
|
+
raise ArgumentError, "pass the code you want to execute as `ractor: [ClassName, :method_name]`"
|
461
|
+
end
|
462
|
+
|
463
|
+
# build
|
464
|
+
ractors = Array.new(options.fetch(:count)) do
|
465
|
+
Ractor.new do
|
466
|
+
loop do
|
467
|
+
got = receive
|
468
|
+
(klass, method_name), item, index = got
|
469
|
+
break if index == :break
|
470
|
+
begin
|
471
|
+
Ractor.yield [nil, klass.send(method_name, item), item, index]
|
472
|
+
rescue StandardError => e
|
473
|
+
Ractor.yield [e, nil, item, index]
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# start
|
480
|
+
ractors.dup.each do |ractor|
|
481
|
+
if (set = job_factory.next)
|
482
|
+
item, index = set
|
483
|
+
instrument_start item, index, options
|
484
|
+
ractor.send [callback, item, index]
|
485
|
+
else
|
486
|
+
ractor.send([[nil, nil], nil, :break]) # stop the ractor
|
487
|
+
ractors.delete ractor
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
# replace with new items
|
492
|
+
while (set = job_factory.next)
|
493
|
+
item_next, index_next = set
|
494
|
+
done, (exception, result, item, index) = Ractor.select(*ractors)
|
495
|
+
if exception
|
496
|
+
ractors.delete done
|
497
|
+
break
|
498
|
+
end
|
499
|
+
instrument_finish item, index, result, options
|
500
|
+
results_mutex.synchronize { results[index] = (options[:preserve_results] == false ? nil : result) }
|
501
|
+
|
502
|
+
instrument_start item_next, index_next, options
|
503
|
+
done.send([callback, item_next, index_next])
|
504
|
+
end
|
505
|
+
|
506
|
+
# finish
|
507
|
+
ractors.each do |ractor|
|
508
|
+
(new_exception, result, item, index) = ractor.take
|
509
|
+
exception ||= new_exception
|
510
|
+
next if new_exception
|
511
|
+
instrument_finish item, index, result, options
|
512
|
+
results_mutex.synchronize { results[index] = (options[:preserve_results] == false ? nil : result) }
|
513
|
+
ractor.send([[nil, nil], nil, :break]) # stop the ractor
|
514
|
+
end
|
515
|
+
|
516
|
+
exception || results
|
517
|
+
end
|
518
|
+
|
379
519
|
def work_in_processes(job_factory, options, &blk)
|
380
520
|
workers = create_workers(job_factory, options, &blk)
|
381
521
|
results = []
|
@@ -407,9 +547,9 @@ module Parallel
|
|
407
547
|
results_mutex.synchronize { results[index] = result } # arrays are not threads safe on jRuby
|
408
548
|
rescue StandardError => e
|
409
549
|
exception = e
|
410
|
-
if Kill
|
550
|
+
if exception.is_a?(Kill)
|
411
551
|
(workers - [worker]).each do |w|
|
412
|
-
w.thread
|
552
|
+
w.thread&.kill
|
413
553
|
UserInterruptHandler.kill(w.pid)
|
414
554
|
end
|
415
555
|
end
|
@@ -420,18 +560,19 @@ module Parallel
|
|
420
560
|
end
|
421
561
|
end
|
422
562
|
end
|
563
|
+
|
423
564
|
exception || results
|
424
565
|
end
|
425
566
|
|
426
|
-
def replace_worker(job_factory, workers,
|
567
|
+
def replace_worker(job_factory, workers, index, options, blk)
|
427
568
|
options[:mutex].synchronize do
|
428
569
|
# old worker is no longer used ... stop it
|
429
|
-
worker = workers[
|
570
|
+
worker = workers[index]
|
430
571
|
worker.stop
|
431
572
|
|
432
573
|
# create a new replacement worker
|
433
574
|
running = workers - [worker]
|
434
|
-
workers[
|
575
|
+
workers[index] = worker(job_factory, options.merge(started_workers: running, worker_number: index), &blk)
|
435
576
|
end
|
436
577
|
end
|
437
578
|
|
@@ -473,14 +614,17 @@ module Parallel
|
|
473
614
|
until read.eof?
|
474
615
|
data = Marshal.load(read)
|
475
616
|
item, index = job_factory.unpack(data)
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
617
|
+
|
618
|
+
result =
|
619
|
+
begin
|
620
|
+
call_with_index(item, index, options, &block)
|
621
|
+
# https://github.com/rspec/rspec-support/blob/673133cdd13b17077b3d88ece8d7380821f8d7dc/lib/rspec/support.rb#L132-L140
|
622
|
+
rescue NoMemoryError, SignalException, Interrupt, SystemExit # rubocop:disable Lint/ShadowedException
|
623
|
+
raise $!
|
624
|
+
rescue Exception # # rubocop:disable Lint/RescueException
|
625
|
+
ExceptionWrapper.new($!)
|
626
|
+
end
|
627
|
+
|
484
628
|
begin
|
485
629
|
Marshal.dump(result, write)
|
486
630
|
rescue Errno::EPIPE
|
@@ -503,21 +647,62 @@ module Parallel
|
|
503
647
|
def call_with_index(item, index, options, &block)
|
504
648
|
args = [item]
|
505
649
|
args << index if options[:with_index]
|
650
|
+
results = block.call(*args)
|
506
651
|
if options[:return_results]
|
507
|
-
|
652
|
+
results
|
508
653
|
else
|
509
|
-
block.call(*args)
|
510
654
|
nil # avoid GC overhead of passing large results around
|
511
655
|
end
|
512
656
|
end
|
513
657
|
|
514
658
|
def with_instrumentation(item, index, options)
|
515
|
-
|
516
|
-
on_finish = options[:finish]
|
517
|
-
options[:mutex].synchronize { on_start.call(item, index) } if on_start
|
659
|
+
instrument_start(item, index, options)
|
518
660
|
result = yield
|
519
|
-
|
661
|
+
instrument_finish(item, index, result, options)
|
520
662
|
result unless options[:preserve_results] == false
|
521
663
|
end
|
664
|
+
|
665
|
+
def instrument_finish(item, index, result, options)
|
666
|
+
return unless (on_finish = options[:finish])
|
667
|
+
return instrument_finish_in_order(item, index, result, options) if options[:finish_in_order]
|
668
|
+
options[:mutex].synchronize { on_finish.call(item, index, result) }
|
669
|
+
end
|
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
|
+
|
694
|
+
def instrument_start(item, index, options)
|
695
|
+
return unless (on_start = options[:start])
|
696
|
+
options[:mutex].synchronize { on_start.call(item, index) }
|
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
|
522
707
|
end
|
523
708
|
end
|
metadata
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.27.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Grosser
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-04-14 00:00:00.000000000 Z
|
12
11
|
dependencies: []
|
13
|
-
description:
|
14
12
|
email: michael@grosser.it
|
15
13
|
executables: []
|
16
14
|
extensions: []
|
@@ -18,17 +16,15 @@ extra_rdoc_files: []
|
|
18
16
|
files:
|
19
17
|
- MIT-LICENSE.txt
|
20
18
|
- lib/parallel.rb
|
21
|
-
- lib/parallel/processor_count.rb
|
22
19
|
- lib/parallel/version.rb
|
23
20
|
homepage: https://github.com/grosser/parallel
|
24
21
|
licenses:
|
25
22
|
- MIT
|
26
23
|
metadata:
|
27
24
|
bug_tracker_uri: https://github.com/grosser/parallel/issues
|
28
|
-
documentation_uri: https://github.com/grosser/parallel/blob/v1.
|
29
|
-
source_code_uri: https://github.com/grosser/parallel/tree/v1.
|
25
|
+
documentation_uri: https://github.com/grosser/parallel/blob/v1.27.0/Readme.md
|
26
|
+
source_code_uri: https://github.com/grosser/parallel/tree/v1.27.0
|
30
27
|
wiki_uri: https://github.com/grosser/parallel/wiki
|
31
|
-
post_install_message:
|
32
28
|
rdoc_options: []
|
33
29
|
require_paths:
|
34
30
|
- lib
|
@@ -36,15 +32,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
36
32
|
requirements:
|
37
33
|
- - ">="
|
38
34
|
- !ruby/object:Gem::Version
|
39
|
-
version: '2.
|
35
|
+
version: '2.7'
|
40
36
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
37
|
requirements:
|
42
38
|
- - ">="
|
43
39
|
- !ruby/object:Gem::Version
|
44
40
|
version: '0'
|
45
41
|
requirements: []
|
46
|
-
rubygems_version: 3.
|
47
|
-
signing_key:
|
42
|
+
rubygems_version: 3.6.2
|
48
43
|
specification_version: 4
|
49
44
|
summary: Run any kind of code in parallel processes
|
50
45
|
test_files: []
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'etc'
|
2
|
-
|
3
|
-
module Parallel
|
4
|
-
# TODO: inline this method into parallel.rb and kill physical_processor_count in next major release
|
5
|
-
module ProcessorCount
|
6
|
-
# Number of processors seen by the OS, used for process scheduling
|
7
|
-
def processor_count
|
8
|
-
@processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || Etc.nprocessors)
|
9
|
-
end
|
10
|
-
|
11
|
-
# Number of physical processor cores on the current system.
|
12
|
-
def physical_processor_count
|
13
|
-
@physical_processor_count ||= begin
|
14
|
-
ppc = case RbConfig::CONFIG["target_os"]
|
15
|
-
when /darwin1/
|
16
|
-
IO.popen("/usr/sbin/sysctl -n hw.physicalcpu").read.to_i
|
17
|
-
when /linux/
|
18
|
-
cores = {} # unique physical ID / core ID combinations
|
19
|
-
phy = 0
|
20
|
-
IO.read("/proc/cpuinfo").scan(/^physical id.*|^core id.*/) do |ln|
|
21
|
-
if ln.start_with?("physical")
|
22
|
-
phy = ln[/\d+/]
|
23
|
-
elsif ln.start_with?("core")
|
24
|
-
cid = phy + ":" + ln[/\d+/]
|
25
|
-
cores[cid] = true if not cores[cid]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
cores.count
|
29
|
-
when /mswin|mingw/
|
30
|
-
require 'win32ole'
|
31
|
-
result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
|
32
|
-
"select NumberOfCores from Win32_Processor")
|
33
|
-
result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
|
34
|
-
else
|
35
|
-
processor_count
|
36
|
-
end
|
37
|
-
# fall back to logical count if physical info is invalid
|
38
|
-
ppc > 0 ? ppc : processor_count
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|