parallel 1.13.0 → 1.20.1
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.rb +66 -46
- data/lib/parallel/processor_count.rb +4 -55
- data/lib/parallel/version.rb +1 -1
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa334cb0d83b8049f260a5e6724d2fd0e65768f85afd0968a2af05d55dda4e0e
|
4
|
+
data.tar.gz: 7ba3ade3a7af4bcfe5944b8d7313b5ec6e4074d27755a83f95e4f8a01d77261e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d470562bd90ab80c66f69b9c1ab016f737bf52e091ac3027c51ea7482eaecd3bd3c186daab756c5d4276b9fb54f0e80f149a8071dc17c31a321ff4fc4d369600
|
7
|
+
data.tar.gz: f01bf1c3a052579c11c3097b02b02a4a30c8e881dbb4916c3ceba6f122aab3a40c276a1de82f7ea7d3790eeff2f994bd20283361151439a3d57b025bdd24dfc8
|
data/lib/parallel.rb
CHANGED
@@ -3,15 +3,21 @@ require 'parallel/version'
|
|
3
3
|
require 'parallel/processor_count'
|
4
4
|
|
5
5
|
module Parallel
|
6
|
-
extend
|
6
|
+
extend ProcessorCount
|
7
|
+
|
8
|
+
Stop = Object.new.freeze
|
7
9
|
|
8
10
|
class DeadWorker < StandardError
|
9
11
|
end
|
10
12
|
|
11
13
|
class Break < StandardError
|
14
|
+
attr_reader :value
|
15
|
+
def initialize(value = nil)
|
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
|
@@ -22,8 +28,6 @@ module Parallel
|
|
22
28
|
end
|
23
29
|
end
|
24
30
|
|
25
|
-
Stop = Object.new
|
26
|
-
|
27
31
|
class ExceptionWrapper
|
28
32
|
attr_reader :exception
|
29
33
|
def initialize(exception)
|
@@ -102,7 +106,7 @@ module Parallel
|
|
102
106
|
item, index = @mutex.synchronize do
|
103
107
|
return if @stopped
|
104
108
|
item = @lambda.call
|
105
|
-
@stopped = (item ==
|
109
|
+
@stopped = (item == Stop)
|
106
110
|
return if @stopped
|
107
111
|
[item, @index += 1]
|
108
112
|
end
|
@@ -201,10 +205,21 @@ module Parallel
|
|
201
205
|
|
202
206
|
class << self
|
203
207
|
def in_threads(options={:count => 2})
|
208
|
+
threads = []
|
204
209
|
count, _ = extract_count_from_options(options)
|
205
|
-
|
206
|
-
|
207
|
-
|
210
|
+
|
211
|
+
Thread.handle_interrupt(Exception => :never) do
|
212
|
+
begin
|
213
|
+
Thread.handle_interrupt(Exception => :immediate) do
|
214
|
+
count.times do |i|
|
215
|
+
threads << Thread.new { yield(i) }
|
216
|
+
end
|
217
|
+
threads.map(&:value)
|
218
|
+
end
|
219
|
+
ensure
|
220
|
+
threads.each(&:kill)
|
221
|
+
end
|
222
|
+
end
|
208
223
|
end
|
209
224
|
|
210
225
|
def in_processes(options = {}, &block)
|
@@ -219,12 +234,12 @@ module Parallel
|
|
219
234
|
|
220
235
|
def any?(*args, &block)
|
221
236
|
raise "You must provide a block when calling #any?" if block.nil?
|
222
|
-
!each(*args) { |*a| raise
|
237
|
+
!each(*args) { |*a| raise Kill if block.call(*a) }
|
223
238
|
end
|
224
239
|
|
225
240
|
def all?(*args, &block)
|
226
241
|
raise "You must provide a block when calling #all?" if block.nil?
|
227
|
-
!!each(*args) { |*a| raise
|
242
|
+
!!each(*args) { |*a| raise Kill unless block.call(*a) }
|
228
243
|
end
|
229
244
|
|
230
245
|
def each_with_index(array, options={}, &block)
|
@@ -259,26 +274,33 @@ module Parallel
|
|
259
274
|
options[:return_results] = (options[:preserve_results] != false || !!options[:finish])
|
260
275
|
add_progress_bar!(job_factory, options)
|
261
276
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
277
|
+
result =
|
278
|
+
if size == 0
|
279
|
+
work_direct(job_factory, options, &block)
|
280
|
+
elsif method == :in_threads
|
281
|
+
work_in_threads(job_factory, options.merge(:count => size), &block)
|
282
|
+
else
|
283
|
+
work_in_processes(job_factory, options.merge(:count => size), &block)
|
284
|
+
end
|
285
|
+
|
286
|
+
return result.value if result.is_a?(Break)
|
287
|
+
raise result if result.is_a?(Exception)
|
288
|
+
options[:return_results] ? result : source
|
272
289
|
end
|
273
290
|
|
274
291
|
def map_with_index(array, options={}, &block)
|
275
292
|
map(array, options.merge(:with_index => true), &block)
|
276
293
|
end
|
277
294
|
|
295
|
+
def flat_map(*args, &block)
|
296
|
+
map(*args, &block).flatten(1)
|
297
|
+
end
|
298
|
+
|
278
299
|
def worker_number
|
279
300
|
Thread.current[:parallel_worker_number]
|
280
301
|
end
|
281
302
|
|
303
|
+
# TODO: this does not work when doing threads in forks, so should remove and yield the number instead if needed
|
282
304
|
def worker_number=(worker_num)
|
283
305
|
Thread.current[:parallel_worker_number] = worker_num
|
284
306
|
end
|
@@ -324,7 +346,7 @@ module Parallel
|
|
324
346
|
rescue
|
325
347
|
exception = $!
|
326
348
|
end
|
327
|
-
|
349
|
+
exception || results
|
328
350
|
ensure
|
329
351
|
self.worker_number = nil
|
330
352
|
end
|
@@ -351,15 +373,11 @@ module Parallel
|
|
351
373
|
end
|
352
374
|
end
|
353
375
|
|
354
|
-
|
376
|
+
exception || results
|
355
377
|
end
|
356
378
|
|
357
379
|
def work_in_processes(job_factory, options, &blk)
|
358
|
-
workers =
|
359
|
-
[] # we create workers per job and not beforehand
|
360
|
-
else
|
361
|
-
create_workers(job_factory, options, &blk)
|
362
|
-
end
|
380
|
+
workers = create_workers(job_factory, options, &blk)
|
363
381
|
results = []
|
364
382
|
results_mutex = Mutex.new # arrays are not thread-safe
|
365
383
|
exception = nil
|
@@ -367,6 +385,8 @@ module Parallel
|
|
367
385
|
UserInterruptHandler.kill_on_ctrl_c(workers.map(&:pid), options) do
|
368
386
|
in_threads(options) do |i|
|
369
387
|
worker = workers[i]
|
388
|
+
worker.thread = Thread.current
|
389
|
+
worked = false
|
370
390
|
|
371
391
|
begin
|
372
392
|
loop do
|
@@ -375,40 +395,39 @@ module Parallel
|
|
375
395
|
break unless index
|
376
396
|
|
377
397
|
if options[:isolation]
|
378
|
-
worker = replace_worker(job_factory, workers, i, options, blk)
|
398
|
+
worker = replace_worker(job_factory, workers, i, options, blk) if worked
|
399
|
+
worked = true
|
400
|
+
worker.thread = Thread.current
|
379
401
|
end
|
380
402
|
|
381
|
-
worker.thread = Thread.current
|
382
|
-
|
383
403
|
begin
|
384
404
|
result = with_instrumentation item, index, options do
|
385
405
|
worker.work(job_factory.pack(item, index))
|
386
406
|
end
|
387
407
|
results_mutex.synchronize { results[index] = result } # arrays are not threads safe on jRuby
|
388
|
-
rescue
|
389
|
-
exception =
|
390
|
-
if
|
408
|
+
rescue StandardError => e
|
409
|
+
exception = e
|
410
|
+
if Kill === exception
|
391
411
|
(workers - [worker]).each do |w|
|
392
|
-
w.thread.kill
|
412
|
+
w.thread.kill if w.thread
|
393
413
|
UserInterruptHandler.kill(w.pid)
|
394
414
|
end
|
395
415
|
end
|
396
416
|
end
|
397
417
|
end
|
398
418
|
ensure
|
399
|
-
worker.stop
|
419
|
+
worker.stop
|
400
420
|
end
|
401
421
|
end
|
402
422
|
end
|
403
|
-
|
404
|
-
handle_exception(exception, results)
|
423
|
+
exception || results
|
405
424
|
end
|
406
425
|
|
407
426
|
def replace_worker(job_factory, workers, i, options, blk)
|
408
427
|
options[:mutex].synchronize do
|
409
428
|
# old worker is no longer used ... stop it
|
410
429
|
worker = workers[i]
|
411
|
-
worker.stop
|
430
|
+
worker.stop
|
412
431
|
|
413
432
|
# create a new replacement worker
|
414
433
|
running = workers - [worker]
|
@@ -456,19 +475,20 @@ module Parallel
|
|
456
475
|
item, index = job_factory.unpack(data)
|
457
476
|
result = begin
|
458
477
|
call_with_index(item, index, options, &block)
|
459
|
-
|
478
|
+
# https://github.com/rspec/rspec-support/blob/673133cdd13b17077b3d88ece8d7380821f8d7dc/lib/rspec/support.rb#L132-L140
|
479
|
+
rescue NoMemoryError, SignalException, Interrupt, SystemExit
|
480
|
+
raise $!
|
481
|
+
rescue Exception
|
460
482
|
ExceptionWrapper.new($!)
|
461
483
|
end
|
462
|
-
|
484
|
+
begin
|
485
|
+
Marshal.dump(result, write)
|
486
|
+
rescue Errno::EPIPE
|
487
|
+
return # parent thread already dead
|
488
|
+
end
|
463
489
|
end
|
464
490
|
end
|
465
491
|
|
466
|
-
def handle_exception(exception, results)
|
467
|
-
return nil if [Parallel::Break, Parallel::Kill].include? exception.class
|
468
|
-
raise exception if exception
|
469
|
-
results
|
470
|
-
end
|
471
|
-
|
472
492
|
# options is either a Integer or a Hash with :count
|
473
493
|
def extract_count_from_options(options)
|
474
494
|
if options.is_a?(Hash)
|
@@ -1,65 +1,14 @@
|
|
1
|
-
|
2
|
-
require 'etc'
|
3
|
-
end
|
1
|
+
require 'etc'
|
4
2
|
|
5
3
|
module Parallel
|
4
|
+
# TODO: inline this method into parallel.rb and kill physical_processor_count in next major release
|
6
5
|
module ProcessorCount
|
7
|
-
# Number of processors seen by the OS
|
8
|
-
#
|
9
|
-
# * AIX: /usr/sbin/pmcycles (AIX 5+), /usr/sbin/lsdev
|
10
|
-
# * BSD: /sbin/sysctl
|
11
|
-
# * Cygwin: /proc/cpuinfo
|
12
|
-
# * Darwin: /usr/bin/hwprefs, /usr/sbin/sysctl
|
13
|
-
# * HP-UX: /usr/sbin/ioscan
|
14
|
-
# * IRIX: /usr/sbin/sysconf
|
15
|
-
# * Linux: /proc/cpuinfo
|
16
|
-
# * Minix 3+: /proc/cpuinfo
|
17
|
-
# * Solaris: /usr/sbin/psrinfo
|
18
|
-
# * Tru64 UNIX: /usr/sbin/psrinfo
|
19
|
-
# * UnixWare: /usr/sbin/psrinfo
|
20
|
-
#
|
6
|
+
# Number of processors seen by the OS, used for process scheduling
|
21
7
|
def processor_count
|
22
|
-
@processor_count ||=
|
23
|
-
if defined?(Etc) && Etc.respond_to?(:nprocessors)
|
24
|
-
Etc.nprocessors
|
25
|
-
else
|
26
|
-
os_name = RbConfig::CONFIG["target_os"]
|
27
|
-
if os_name =~ /mingw|mswin/
|
28
|
-
require 'win32ole'
|
29
|
-
result = WIN32OLE.connect("winmgmts://").ExecQuery(
|
30
|
-
"select NumberOfLogicalProcessors from Win32_Processor")
|
31
|
-
result.to_enum.collect(&:NumberOfLogicalProcessors).reduce(:+)
|
32
|
-
elsif File.readable?("/proc/cpuinfo")
|
33
|
-
IO.read("/proc/cpuinfo").scan(/^processor/).size
|
34
|
-
elsif File.executable?("/usr/bin/hwprefs")
|
35
|
-
IO.popen("/usr/bin/hwprefs thread_count").read.to_i
|
36
|
-
elsif File.executable?("/usr/sbin/psrinfo")
|
37
|
-
IO.popen("/usr/sbin/psrinfo").read.scan(/^.*on-*line/).size
|
38
|
-
elsif File.executable?("/usr/sbin/ioscan")
|
39
|
-
IO.popen("/usr/sbin/ioscan -kC processor") do |out|
|
40
|
-
out.read.scan(/^.*processor/).size
|
41
|
-
end
|
42
|
-
elsif File.executable?("/usr/sbin/pmcycles")
|
43
|
-
IO.popen("/usr/sbin/pmcycles -m").read.count("\n")
|
44
|
-
elsif File.executable?("/usr/sbin/lsdev")
|
45
|
-
IO.popen("/usr/sbin/lsdev -Cc processor -S 1").read.count("\n")
|
46
|
-
elsif File.executable?("/usr/sbin/sysconf") and os_name =~ /irix/i
|
47
|
-
IO.popen("/usr/sbin/sysconf NPROC_ONLN").read.to_i
|
48
|
-
elsif File.executable?("/usr/sbin/sysctl")
|
49
|
-
IO.popen("/usr/sbin/sysctl -n hw.ncpu").read.to_i
|
50
|
-
elsif File.executable?("/sbin/sysctl")
|
51
|
-
IO.popen("/sbin/sysctl -n hw.ncpu").read.to_i
|
52
|
-
else
|
53
|
-
$stderr.puts "Unknown platform: " + RbConfig::CONFIG["target_os"]
|
54
|
-
$stderr.puts "Assuming 1 processor."
|
55
|
-
1
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
8
|
+
@processor_count ||= Integer(ENV['PARALLEL_PROCESSOR_COUNT'] || Etc.nprocessors)
|
59
9
|
end
|
60
10
|
|
61
11
|
# Number of physical processor cores on the current system.
|
62
|
-
#
|
63
12
|
def physical_processor_count
|
64
13
|
@physical_processor_count ||= begin
|
65
14
|
ppc = case RbConfig::CONFIG["target_os"]
|
data/lib/parallel/version.rb
CHANGED
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.20.1
|
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: 2020-11-22 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.20.1/Readme.md
|
29
|
+
source_code_uri: https://github.com/grosser/parallel/tree/v1.20.1
|
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:
|
39
|
+
version: '2.4'
|
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
|
-
|
43
|
-
rubygems_version: 2.7.6
|
46
|
+
rubygems_version: 3.1.3
|
44
47
|
signing_key:
|
45
48
|
specification_version: 4
|
46
49
|
summary: Run any kind of code in parallel processes
|