parallel 1.19.2 → 1.24.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 +224 -72
- metadata +6 -7
- 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: f7b4a5662ef68724c75c2d655d9bd09ad109edc02d3199a0744093544608f74b
|
|
4
|
+
data.tar.gz: 247f7f3745c42cdafeb5d403fff250e99b99a56d4dc4948050dcf20ecb60d183
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 18f62ea9fefb30bda9b89f0189074da99572c5c17fb93ba28e553b0eb9f6d7a61bd70ba423004b138b05c3c86f8e04fd32fce81da40a68c0bdca39e263b8b892
|
|
7
|
+
data.tar.gz: dca61c9e3cab22de0ad064c96c55afc88177214108d6bdbfb8e9a93343f23d6ee321c83aa6c4cfa9ee33da79d01802d7b952f3dd0360f9cca26e5da78a4117fa
|
data/lib/parallel/version.rb
CHANGED
data/lib/parallel.rb
CHANGED
|
@@ -1,31 +1,37 @@
|
|
|
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
|
-
|
|
6
|
+
Stop = Object.new.freeze
|
|
7
7
|
|
|
8
8
|
class DeadWorker < StandardError
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
class Break < StandardError
|
|
12
|
+
attr_reader :value
|
|
13
|
+
|
|
14
|
+
def initialize(value = nil)
|
|
15
|
+
super()
|
|
16
|
+
@value = value
|
|
17
|
+
end
|
|
12
18
|
end
|
|
13
19
|
|
|
14
|
-
class Kill <
|
|
20
|
+
class Kill < Break
|
|
15
21
|
end
|
|
16
22
|
|
|
17
23
|
class UndumpableException < StandardError
|
|
18
24
|
attr_reader :backtrace
|
|
25
|
+
|
|
19
26
|
def initialize(original)
|
|
20
27
|
super "#{original.class}: #{original.message}"
|
|
21
28
|
@backtrace = original.backtrace
|
|
22
29
|
end
|
|
23
30
|
end
|
|
24
31
|
|
|
25
|
-
Stop = Object.new.freeze
|
|
26
|
-
|
|
27
32
|
class ExceptionWrapper
|
|
28
33
|
attr_reader :exception
|
|
34
|
+
|
|
29
35
|
def initialize(exception)
|
|
30
36
|
# Remove the bindings stack added by the better_errors gem,
|
|
31
37
|
# because it cannot be marshalled
|
|
@@ -36,7 +42,7 @@ module Parallel
|
|
|
36
42
|
@exception =
|
|
37
43
|
begin
|
|
38
44
|
Marshal.dump(exception) && exception
|
|
39
|
-
rescue
|
|
45
|
+
rescue StandardError
|
|
40
46
|
UndumpableException.new(exception)
|
|
41
47
|
end
|
|
42
48
|
end
|
|
@@ -45,8 +51,11 @@ module Parallel
|
|
|
45
51
|
class Worker
|
|
46
52
|
attr_reader :pid, :read, :write
|
|
47
53
|
attr_accessor :thread
|
|
54
|
+
|
|
48
55
|
def initialize(read, write, pid)
|
|
49
|
-
@read
|
|
56
|
+
@read = read
|
|
57
|
+
@write = write
|
|
58
|
+
@pid = pid
|
|
50
59
|
end
|
|
51
60
|
|
|
52
61
|
def stop
|
|
@@ -73,7 +82,7 @@ module Parallel
|
|
|
73
82
|
rescue EOFError
|
|
74
83
|
raise DeadWorker
|
|
75
84
|
end
|
|
76
|
-
raise result.exception if ExceptionWrapper
|
|
85
|
+
raise result.exception if result.is_a?(ExceptionWrapper)
|
|
77
86
|
result
|
|
78
87
|
end
|
|
79
88
|
|
|
@@ -102,7 +111,7 @@ module Parallel
|
|
|
102
111
|
item, index = @mutex.synchronize do
|
|
103
112
|
return if @stopped
|
|
104
113
|
item = @lambda.call
|
|
105
|
-
@stopped = (item ==
|
|
114
|
+
@stopped = (item == Stop)
|
|
106
115
|
return if @stopped
|
|
107
116
|
[item, @index += 1]
|
|
108
117
|
end
|
|
@@ -140,7 +149,7 @@ module Parallel
|
|
|
140
149
|
end
|
|
141
150
|
|
|
142
151
|
def queue_wrapper(array)
|
|
143
|
-
array.respond_to?(:num_waiting) && array.respond_to?(:pop) &&
|
|
152
|
+
array.respond_to?(:num_waiting) && array.respond_to?(:pop) && -> { array.pop(false) }
|
|
144
153
|
end
|
|
145
154
|
end
|
|
146
155
|
|
|
@@ -156,7 +165,7 @@ module Parallel
|
|
|
156
165
|
|
|
157
166
|
if @to_be_killed.empty?
|
|
158
167
|
old_interrupt = trap_interrupt(signal) do
|
|
159
|
-
|
|
168
|
+
warn 'Parallel execution interrupted, exiting ...'
|
|
160
169
|
@to_be_killed.flatten.each { |pid| kill(pid) }
|
|
161
170
|
end
|
|
162
171
|
end
|
|
@@ -200,46 +209,44 @@ module Parallel
|
|
|
200
209
|
end
|
|
201
210
|
|
|
202
211
|
class << self
|
|
203
|
-
def in_threads(options={:
|
|
212
|
+
def in_threads(options = { count: 2 })
|
|
204
213
|
threads = []
|
|
205
|
-
count,
|
|
214
|
+
count, = extract_count_from_options(options)
|
|
206
215
|
|
|
207
216
|
Thread.handle_interrupt(Exception => :never) do
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
threads << Thread.new { yield(i) }
|
|
212
|
-
end
|
|
213
|
-
threads.map(&:value)
|
|
217
|
+
Thread.handle_interrupt(Exception => :immediate) do
|
|
218
|
+
count.times do |i|
|
|
219
|
+
threads << Thread.new { yield(i) }
|
|
214
220
|
end
|
|
215
|
-
|
|
216
|
-
threads.each(&:kill)
|
|
221
|
+
threads.map(&:value)
|
|
217
222
|
end
|
|
223
|
+
ensure
|
|
224
|
+
threads.each(&:kill)
|
|
218
225
|
end
|
|
219
226
|
end
|
|
220
227
|
|
|
221
228
|
def in_processes(options = {}, &block)
|
|
222
229
|
count, options = extract_count_from_options(options)
|
|
223
230
|
count ||= processor_count
|
|
224
|
-
map(0...count, options.merge(:
|
|
231
|
+
map(0...count, options.merge(in_processes: count), &block)
|
|
225
232
|
end
|
|
226
233
|
|
|
227
|
-
def each(array, options={}, &block)
|
|
228
|
-
map(array, options.merge(:
|
|
234
|
+
def each(array, options = {}, &block)
|
|
235
|
+
map(array, options.merge(preserve_results: false), &block)
|
|
229
236
|
end
|
|
230
237
|
|
|
231
238
|
def any?(*args, &block)
|
|
232
239
|
raise "You must provide a block when calling #any?" if block.nil?
|
|
233
|
-
!each(*args) { |*a| raise
|
|
240
|
+
!each(*args) { |*a| raise Kill if block.call(*a) }
|
|
234
241
|
end
|
|
235
242
|
|
|
236
243
|
def all?(*args, &block)
|
|
237
244
|
raise "You must provide a block when calling #all?" if block.nil?
|
|
238
|
-
!!each(*args) { |*a| raise
|
|
245
|
+
!!each(*args) { |*a| raise Kill unless block.call(*a) }
|
|
239
246
|
end
|
|
240
247
|
|
|
241
|
-
def each_with_index(array, options={}, &block)
|
|
242
|
-
each(array, options.merge(:
|
|
248
|
+
def each_with_index(array, options = {}, &block)
|
|
249
|
+
each(array, options.merge(with_index: true), &block)
|
|
243
250
|
end
|
|
244
251
|
|
|
245
252
|
def map(source, options = {}, &block)
|
|
@@ -247,13 +254,16 @@ module Parallel
|
|
|
247
254
|
options[:mutex] = Mutex.new
|
|
248
255
|
|
|
249
256
|
if options[:in_processes] && options[:in_threads]
|
|
250
|
-
raise ArgumentError
|
|
251
|
-
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])
|
|
252
259
|
method = :in_threads
|
|
253
260
|
size = options[method] || processor_count
|
|
254
261
|
elsif options[:in_threads]
|
|
255
262
|
method = :in_threads
|
|
256
263
|
size = options[method]
|
|
264
|
+
elsif options[:in_ractors]
|
|
265
|
+
method = :in_ractors
|
|
266
|
+
size = options[method]
|
|
257
267
|
else
|
|
258
268
|
method = :in_processes
|
|
259
269
|
if Process.respond_to?(:fork)
|
|
@@ -270,26 +280,73 @@ module Parallel
|
|
|
270
280
|
options[:return_results] = (options[:preserve_results] != false || !!options[:finish])
|
|
271
281
|
add_progress_bar!(job_factory, options)
|
|
272
282
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
+
elsif method == :in_ractors
|
|
289
|
+
work_in_ractors(job_factory, options.merge(count: size), &block)
|
|
290
|
+
else
|
|
291
|
+
work_in_processes(job_factory, options.merge(count: size), &block)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
return result.value if result.is_a?(Break)
|
|
295
|
+
raise result if result.is_a?(Exception)
|
|
296
|
+
options[:return_results] ? result : source
|
|
283
297
|
end
|
|
284
298
|
|
|
285
|
-
def map_with_index(array, options={}, &block)
|
|
286
|
-
map(array, options.merge(:
|
|
299
|
+
def map_with_index(array, options = {}, &block)
|
|
300
|
+
map(array, options.merge(with_index: true), &block)
|
|
287
301
|
end
|
|
288
302
|
|
|
289
303
|
def flat_map(*args, &block)
|
|
290
304
|
map(*args, &block).flatten(1)
|
|
291
305
|
end
|
|
292
306
|
|
|
307
|
+
def filter_map(*args, &block)
|
|
308
|
+
map(*args, &block).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
|
+
require 'win32ole'
|
|
332
|
+
result_set = WIN32OLE.connect("winmgmts://").ExecQuery(
|
|
333
|
+
"select NumberOfCores from Win32_Processor"
|
|
334
|
+
)
|
|
335
|
+
result_set.to_enum.collect(&:NumberOfCores).reduce(:+)
|
|
336
|
+
else
|
|
337
|
+
processor_count
|
|
338
|
+
end
|
|
339
|
+
# fall back to logical count if physical info is invalid
|
|
340
|
+
ppc > 0 ? ppc : processor_count
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Number of processors seen by the OS, used for process scheduling
|
|
345
|
+
def processor_count
|
|
346
|
+
require 'etc'
|
|
347
|
+
@processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || Etc.nprocessors)
|
|
348
|
+
end
|
|
349
|
+
|
|
293
350
|
def worker_number
|
|
294
351
|
Thread.current[:parallel_worker_number]
|
|
295
352
|
end
|
|
@@ -337,10 +394,10 @@ module Parallel
|
|
|
337
394
|
call_with_index(item, index, options, &block)
|
|
338
395
|
end
|
|
339
396
|
end
|
|
340
|
-
rescue
|
|
397
|
+
rescue StandardError
|
|
341
398
|
exception = $!
|
|
342
399
|
end
|
|
343
|
-
|
|
400
|
+
exception || results
|
|
344
401
|
ensure
|
|
345
402
|
self.worker_number = nil
|
|
346
403
|
end
|
|
@@ -361,13 +418,79 @@ module Parallel
|
|
|
361
418
|
call_with_index(item, index, options, &block)
|
|
362
419
|
end
|
|
363
420
|
results_mutex.synchronize { results[index] = result }
|
|
364
|
-
rescue
|
|
421
|
+
rescue StandardError
|
|
365
422
|
exception = $!
|
|
366
423
|
end
|
|
367
424
|
end
|
|
368
425
|
end
|
|
369
426
|
|
|
370
|
-
|
|
427
|
+
exception || results
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def work_in_ractors(job_factory, options)
|
|
431
|
+
exception = nil
|
|
432
|
+
results = []
|
|
433
|
+
results_mutex = Mutex.new # arrays are not thread-safe on jRuby
|
|
434
|
+
|
|
435
|
+
callback = options[:ractor]
|
|
436
|
+
if block_given? || !callback
|
|
437
|
+
raise ArgumentError, "pass the code you want to execute as `ractor: [ClassName, :method_name]`"
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# build
|
|
441
|
+
ractors = Array.new(options.fetch(:count)) do
|
|
442
|
+
Ractor.new do
|
|
443
|
+
loop do
|
|
444
|
+
got = receive
|
|
445
|
+
(klass, method_name), item, index = got
|
|
446
|
+
break if index == :break
|
|
447
|
+
begin
|
|
448
|
+
Ractor.yield [nil, klass.send(method_name, item), item, index]
|
|
449
|
+
rescue StandardError => e
|
|
450
|
+
Ractor.yield [e, nil, item, index]
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# start
|
|
457
|
+
ractors.dup.each do |ractor|
|
|
458
|
+
if set = job_factory.next
|
|
459
|
+
item, index = set
|
|
460
|
+
instrument_start item, index, options
|
|
461
|
+
ractor.send [callback, item, index]
|
|
462
|
+
else
|
|
463
|
+
ractor.send([[nil, nil], nil, :break]) # stop the ractor
|
|
464
|
+
ractors.delete ractor
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
# replace with new items
|
|
469
|
+
while set = job_factory.next
|
|
470
|
+
item_next, index_next = set
|
|
471
|
+
done, (exception, result, item, index) = Ractor.select(*ractors)
|
|
472
|
+
if exception
|
|
473
|
+
ractors.delete done
|
|
474
|
+
break
|
|
475
|
+
end
|
|
476
|
+
instrument_finish item, index, result, options
|
|
477
|
+
results_mutex.synchronize { results[index] = (options[:preserve_results] == false ? nil : result) }
|
|
478
|
+
|
|
479
|
+
instrument_start item_next, index_next, options
|
|
480
|
+
done.send([callback, item_next, index_next])
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# finish
|
|
484
|
+
ractors.each do |ractor|
|
|
485
|
+
(new_exception, result, item, index) = ractor.take
|
|
486
|
+
exception ||= new_exception
|
|
487
|
+
next if new_exception
|
|
488
|
+
instrument_finish item, index, result, options
|
|
489
|
+
results_mutex.synchronize { results[index] = (options[:preserve_results] == false ? nil : result) }
|
|
490
|
+
ractor.send([[nil, nil], nil, :break]) # stop the ractor
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
exception || results
|
|
371
494
|
end
|
|
372
495
|
|
|
373
496
|
def work_in_processes(job_factory, options, &blk)
|
|
@@ -401,9 +524,9 @@ module Parallel
|
|
|
401
524
|
results_mutex.synchronize { results[index] = result } # arrays are not threads safe on jRuby
|
|
402
525
|
rescue StandardError => e
|
|
403
526
|
exception = e
|
|
404
|
-
if
|
|
527
|
+
if exception.is_a?(Kill)
|
|
405
528
|
(workers - [worker]).each do |w|
|
|
406
|
-
w.thread
|
|
529
|
+
w.thread&.kill
|
|
407
530
|
UserInterruptHandler.kill(w.pid)
|
|
408
531
|
end
|
|
409
532
|
end
|
|
@@ -415,18 +538,18 @@ module Parallel
|
|
|
415
538
|
end
|
|
416
539
|
end
|
|
417
540
|
|
|
418
|
-
|
|
541
|
+
exception || results
|
|
419
542
|
end
|
|
420
543
|
|
|
421
|
-
def replace_worker(job_factory, workers,
|
|
544
|
+
def replace_worker(job_factory, workers, index, options, blk)
|
|
422
545
|
options[:mutex].synchronize do
|
|
423
546
|
# old worker is no longer used ... stop it
|
|
424
|
-
worker = workers[
|
|
547
|
+
worker = workers[index]
|
|
425
548
|
worker.stop
|
|
426
549
|
|
|
427
550
|
# create a new replacement worker
|
|
428
551
|
running = workers - [worker]
|
|
429
|
-
workers[
|
|
552
|
+
workers[index] = worker(job_factory, options.merge(started_workers: running, worker_number: index), &blk)
|
|
430
553
|
end
|
|
431
554
|
end
|
|
432
555
|
|
|
@@ -468,14 +591,17 @@ module Parallel
|
|
|
468
591
|
until read.eof?
|
|
469
592
|
data = Marshal.load(read)
|
|
470
593
|
item, index = job_factory.unpack(data)
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
594
|
+
|
|
595
|
+
result =
|
|
596
|
+
begin
|
|
597
|
+
call_with_index(item, index, options, &block)
|
|
598
|
+
# https://github.com/rspec/rspec-support/blob/673133cdd13b17077b3d88ece8d7380821f8d7dc/lib/rspec/support.rb#L132-L140
|
|
599
|
+
rescue NoMemoryError, SignalException, Interrupt, SystemExit # rubocop:disable Lint/ShadowedException
|
|
600
|
+
raise $!
|
|
601
|
+
rescue Exception # # rubocop:disable Lint/RescueException
|
|
602
|
+
ExceptionWrapper.new($!)
|
|
603
|
+
end
|
|
604
|
+
|
|
479
605
|
begin
|
|
480
606
|
Marshal.dump(result, write)
|
|
481
607
|
rescue Errno::EPIPE
|
|
@@ -484,12 +610,6 @@ module Parallel
|
|
|
484
610
|
end
|
|
485
611
|
end
|
|
486
612
|
|
|
487
|
-
def handle_exception(exception, results)
|
|
488
|
-
return nil if [Parallel::Break, Parallel::Kill].include? exception.class
|
|
489
|
-
raise exception if exception
|
|
490
|
-
results
|
|
491
|
-
end
|
|
492
|
-
|
|
493
613
|
# options is either a Integer or a Hash with :count
|
|
494
614
|
def extract_count_from_options(options)
|
|
495
615
|
if options.is_a?(Hash)
|
|
@@ -504,21 +624,53 @@ module Parallel
|
|
|
504
624
|
def call_with_index(item, index, options, &block)
|
|
505
625
|
args = [item]
|
|
506
626
|
args << index if options[:with_index]
|
|
627
|
+
results = block.call(*args)
|
|
507
628
|
if options[:return_results]
|
|
508
|
-
|
|
629
|
+
results
|
|
509
630
|
else
|
|
510
|
-
block.call(*args)
|
|
511
631
|
nil # avoid GC overhead of passing large results around
|
|
512
632
|
end
|
|
513
633
|
end
|
|
514
634
|
|
|
515
635
|
def with_instrumentation(item, index, options)
|
|
516
|
-
|
|
517
|
-
on_finish = options[:finish]
|
|
518
|
-
options[:mutex].synchronize { on_start.call(item, index) } if on_start
|
|
636
|
+
instrument_start(item, index, options)
|
|
519
637
|
result = yield
|
|
520
|
-
|
|
638
|
+
instrument_finish(item, index, result, options)
|
|
521
639
|
result unless options[:preserve_results] == false
|
|
522
640
|
end
|
|
641
|
+
|
|
642
|
+
def instrument_finish(item, index, result, options)
|
|
643
|
+
return unless (on_finish = options[:finish])
|
|
644
|
+
return instrument_finish_in_order(item, index, result, options) if options[:finish_in_order]
|
|
645
|
+
options[:mutex].synchronize { on_finish.call(item, index, result) }
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
# yield results in the order of the input items
|
|
649
|
+
# needs to use `options` to store state between executions
|
|
650
|
+
# needs to use `done` index since a nil result would also be valid
|
|
651
|
+
def instrument_finish_in_order(item, index, result, options)
|
|
652
|
+
options[:mutex].synchronize do
|
|
653
|
+
# initialize our state
|
|
654
|
+
options[:finish_done] ||= []
|
|
655
|
+
options[:finish_expecting] ||= 0 # we wait for item at index 0
|
|
656
|
+
|
|
657
|
+
# store current result
|
|
658
|
+
options[:finish_done][index] = [item, result]
|
|
659
|
+
|
|
660
|
+
# yield all results that are now in order
|
|
661
|
+
break unless index == options[:finish_expecting]
|
|
662
|
+
index.upto(options[:finish_done].size).each do |i|
|
|
663
|
+
break unless (done = options[:finish_done][i])
|
|
664
|
+
options[:finish_done][i] = nil # allow GC to free this item and result
|
|
665
|
+
options[:finish].call(done[0], i, done[1])
|
|
666
|
+
options[:finish_expecting] += 1
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
def instrument_start(item, index, options)
|
|
672
|
+
return unless on_start = options[:start]
|
|
673
|
+
options[:mutex].synchronize { on_start.call(item, index) }
|
|
674
|
+
end
|
|
523
675
|
end
|
|
524
676
|
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.
|
|
4
|
+
version: 1.24.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:
|
|
11
|
+
date: 2023-12-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email: michael@grosser.it
|
|
@@ -18,15 +18,14 @@ extra_rdoc_files: []
|
|
|
18
18
|
files:
|
|
19
19
|
- MIT-LICENSE.txt
|
|
20
20
|
- lib/parallel.rb
|
|
21
|
-
- lib/parallel/processor_count.rb
|
|
22
21
|
- lib/parallel/version.rb
|
|
23
22
|
homepage: https://github.com/grosser/parallel
|
|
24
23
|
licenses:
|
|
25
24
|
- MIT
|
|
26
25
|
metadata:
|
|
27
26
|
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.
|
|
27
|
+
documentation_uri: https://github.com/grosser/parallel/blob/v1.24.0/Readme.md
|
|
28
|
+
source_code_uri: https://github.com/grosser/parallel/tree/v1.24.0
|
|
30
29
|
wiki_uri: https://github.com/grosser/parallel/wiki
|
|
31
30
|
post_install_message:
|
|
32
31
|
rdoc_options: []
|
|
@@ -36,14 +35,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
36
35
|
requirements:
|
|
37
36
|
- - ">="
|
|
38
37
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '2.
|
|
38
|
+
version: '2.5'
|
|
40
39
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
40
|
requirements:
|
|
42
41
|
- - ">="
|
|
43
42
|
- !ruby/object:Gem::Version
|
|
44
43
|
version: '0'
|
|
45
44
|
requirements: []
|
|
46
|
-
rubygems_version: 3.1.
|
|
45
|
+
rubygems_version: 3.1.6
|
|
47
46
|
signing_key:
|
|
48
47
|
specification_version: 4
|
|
49
48
|
summary: Run any kind of code in parallel processes
|
|
@@ -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
|