parallel 2.1.0 → 2.2.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/serializer.rb +4 -0
- data/lib/parallel/version.rb +1 -1
- data/lib/parallel.rb +114 -55
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bcd30f5bfe7076b4a0872b389f00057efaae80917298e3d227c160cc8c1be410
|
|
4
|
+
data.tar.gz: d6dd66ee7f75d2e14123c292ce13ac2b448134622c712650c07482986dbd48a3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 11ed4f49a53e9e20d052725911593266b808dfaa7b2392f503d39494b318a16df15ad628b586f93b700f5e22627116c465afff818d61ac2f0ca3aed4dcd1b8c0
|
|
7
|
+
data.tar.gz: af37003c9dc58ae81dac2a80355f5b16db9f54734f06a9c0dc33e73730818f7e81306237f152cd2976399a6453300915b19593e2e6928b480330fa736c516bc6
|
data/lib/parallel/serializer.rb
CHANGED
data/lib/parallel/version.rb
CHANGED
data/lib/parallel.rb
CHANGED
|
@@ -124,7 +124,7 @@ module Parallel
|
|
|
124
124
|
item, index = @mutex.synchronize do
|
|
125
125
|
return if @stopped
|
|
126
126
|
item = @lambda.call
|
|
127
|
-
@stopped = (item
|
|
127
|
+
@stopped = Stop.equal?(item)
|
|
128
128
|
return if @stopped
|
|
129
129
|
[item, @index += 1]
|
|
130
130
|
end
|
|
@@ -178,7 +178,7 @@ module Parallel
|
|
|
178
178
|
|
|
179
179
|
if @to_be_killed.empty?
|
|
180
180
|
old_interrupt = trap_interrupt(signal) do
|
|
181
|
-
warn '
|
|
181
|
+
warn 'parallel: execution interrupted, exiting ...'
|
|
182
182
|
@to_be_killed.flatten.each { |pid| kill(pid) }
|
|
183
183
|
end
|
|
184
184
|
end
|
|
@@ -245,7 +245,7 @@ module Parallel
|
|
|
245
245
|
end
|
|
246
246
|
|
|
247
247
|
def each(array, options = {}, &block)
|
|
248
|
-
map(array, options.merge(
|
|
248
|
+
map(array, options.merge(discard_results: true), &block)
|
|
249
249
|
end
|
|
250
250
|
|
|
251
251
|
def any?(*args, &block)
|
|
@@ -266,9 +266,15 @@ module Parallel
|
|
|
266
266
|
options = options.dup
|
|
267
267
|
options[:mutex] = Mutex.new
|
|
268
268
|
|
|
269
|
-
if options
|
|
270
|
-
raise ArgumentError, "
|
|
271
|
-
|
|
269
|
+
if options.slice(:in_processes, :in_threads, :in_ractors).size > 1
|
|
270
|
+
raise ArgumentError, "Use only one of `in_processes`, `in_threads`, or `in_ractors`."
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
if options[:in_ractors] ? block : options[:ractor]
|
|
274
|
+
raise ArgumentError, "use either in_ractors with :ractor or a not in_ractors and block"
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
if RUBY_PLATFORM.include?('java') && !options[:in_processes]
|
|
272
278
|
method = :in_threads
|
|
273
279
|
size = options[method] || processor_count
|
|
274
280
|
elsif options[:in_threads]
|
|
@@ -282,31 +288,38 @@ module Parallel
|
|
|
282
288
|
if Process.respond_to?(:fork)
|
|
283
289
|
size = options[method] || processor_count
|
|
284
290
|
else
|
|
285
|
-
warn "Process.fork is not supported by this Ruby"
|
|
291
|
+
warn "parallel: Process.fork is not supported by this Ruby"
|
|
286
292
|
size = 0
|
|
287
293
|
end
|
|
288
294
|
end
|
|
289
295
|
|
|
296
|
+
raise ArgumentError, "worker count must be a non-negative Integer" unless size.is_a?(Integer) && size >= 0
|
|
297
|
+
|
|
290
298
|
job_factory = JobFactory.new(source, options[:mutex])
|
|
291
299
|
size = [job_factory.size, size].min
|
|
292
300
|
|
|
293
|
-
|
|
301
|
+
discard_results = options[:discard_results]
|
|
302
|
+
|
|
303
|
+
# finish callback needs the results, careful to do that before add_progress_bar which adds finish
|
|
304
|
+
options[:discard_results] = discard_results && !options[:finish]
|
|
305
|
+
|
|
294
306
|
add_progress_bar!(job_factory, options)
|
|
295
307
|
|
|
296
308
|
result =
|
|
297
309
|
if size == 0
|
|
310
|
+
block = ractor_block(options) if method == :in_ractors
|
|
298
311
|
work_direct(job_factory, options, &block)
|
|
299
312
|
elsif method == :in_threads
|
|
300
313
|
work_in_threads(job_factory, options.merge(count: size), &block)
|
|
301
314
|
elsif method == :in_ractors
|
|
302
|
-
work_in_ractors(job_factory, options.merge(count: size)
|
|
315
|
+
work_in_ractors(job_factory, options.merge(count: size))
|
|
303
316
|
else
|
|
304
317
|
work_in_processes(job_factory, options.merge(count: size), &block)
|
|
305
318
|
end
|
|
306
319
|
|
|
307
320
|
return result.value if result.is_a?(Break)
|
|
308
321
|
raise result if result.is_a?(Exception)
|
|
309
|
-
|
|
322
|
+
discard_results ? source : result
|
|
310
323
|
end
|
|
311
324
|
|
|
312
325
|
def map_with_index(array, options = {}, &block)
|
|
@@ -318,7 +331,7 @@ module Parallel
|
|
|
318
331
|
end
|
|
319
332
|
|
|
320
333
|
def filter_map(...)
|
|
321
|
-
map(...).
|
|
334
|
+
map(...).select { |value| value }
|
|
322
335
|
end
|
|
323
336
|
|
|
324
337
|
# Number of physical processor cores on the current system.
|
|
@@ -379,7 +392,7 @@ module Parallel
|
|
|
379
392
|
end
|
|
380
393
|
if !result || $?.exitstatus != 0
|
|
381
394
|
# Bail out if both commands returned something unexpected
|
|
382
|
-
warn "guessing
|
|
395
|
+
warn "parallel: guessing physical processor count"
|
|
383
396
|
processor_count
|
|
384
397
|
else
|
|
385
398
|
# powershell: "\nNumberOfCores\n-------------\n 4\n\n\n"
|
|
@@ -420,22 +433,24 @@ module Parallel
|
|
|
420
433
|
end
|
|
421
434
|
|
|
422
435
|
def work_direct(job_factory, options, &block)
|
|
436
|
+
previous_worker_number = worker_number
|
|
423
437
|
self.worker_number = 0
|
|
424
438
|
results = []
|
|
425
439
|
exception = nil
|
|
426
440
|
begin
|
|
427
441
|
while (set = job_factory.next)
|
|
428
442
|
item, index = set
|
|
429
|
-
|
|
443
|
+
result = with_instrumentation(item, index, options) do
|
|
430
444
|
call_with_index(item, index, options, &block)
|
|
431
445
|
end
|
|
446
|
+
results << result unless options[:discard_results]
|
|
432
447
|
end
|
|
433
448
|
rescue StandardError
|
|
434
449
|
exception = $!
|
|
435
450
|
end
|
|
436
451
|
exception || results
|
|
437
452
|
ensure
|
|
438
|
-
self.worker_number =
|
|
453
|
+
self.worker_number = previous_worker_number
|
|
439
454
|
end
|
|
440
455
|
|
|
441
456
|
def work_in_threads(job_factory, options, &block)
|
|
@@ -453,7 +468,7 @@ module Parallel
|
|
|
453
468
|
result = with_instrumentation item, index, options do
|
|
454
469
|
call_with_index(item, index, options, &block)
|
|
455
470
|
end
|
|
456
|
-
results_mutex.synchronize { results[index] = result }
|
|
471
|
+
results_mutex.synchronize { results[index] = result } unless options[:discard_results]
|
|
457
472
|
rescue StandardError
|
|
458
473
|
exception = $!
|
|
459
474
|
end
|
|
@@ -482,55 +497,70 @@ module Parallel
|
|
|
482
497
|
ports[port] = ractor
|
|
483
498
|
end
|
|
484
499
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
500
|
+
begin
|
|
501
|
+
# start by sending 1 item each
|
|
502
|
+
ports.dup.each do |port, ractor|
|
|
503
|
+
if (job = job_factory.next)
|
|
504
|
+
ractor_send ractor, callback, job, options
|
|
505
|
+
else # not enough work, `receive` would hang
|
|
506
|
+
ractor_stop ractor
|
|
507
|
+
ports.delete port
|
|
508
|
+
end
|
|
494
509
|
end
|
|
495
|
-
end
|
|
496
510
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
511
|
+
# receive result and send new items
|
|
512
|
+
while (job = job_factory.next)
|
|
513
|
+
# receive result
|
|
514
|
+
done_port, (exception, result, item_prev, index_prev) = Ractor.select(*ports.keys)
|
|
515
|
+
done_ractor = ports[done_port]
|
|
516
|
+
if exception
|
|
517
|
+
ractor_stop done_ractor
|
|
518
|
+
ports.delete done_port
|
|
519
|
+
break
|
|
520
|
+
end
|
|
521
|
+
ractor_result item_prev, index_prev, result, results, results_mutex, options
|
|
507
522
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
done_ractor.send([callback, item_next, index_next])
|
|
512
|
-
end
|
|
523
|
+
# send new
|
|
524
|
+
ractor_send done_ractor, callback, job, options
|
|
525
|
+
end
|
|
513
526
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
527
|
+
# finish by receiving the last results
|
|
528
|
+
ports.dup.each do |port, ractor|
|
|
529
|
+
(new_exception, result, item, index) = use_port ? port.receive : ractor.take
|
|
530
|
+
exception ||= new_exception
|
|
531
|
+
ractor_result item, index, result, results, results_mutex, options unless new_exception
|
|
532
|
+
ractor_stop ractor
|
|
533
|
+
ports.delete port
|
|
534
|
+
end
|
|
535
|
+
ensure # close any ports that remained open in case something blew up
|
|
536
|
+
ports.each_value do |ractor|
|
|
537
|
+
ractor_stop(ractor)
|
|
538
|
+
ractor.take unless use_port
|
|
539
|
+
rescue Ractor::ClosedError, Ractor::RemoteError
|
|
540
|
+
nil
|
|
541
|
+
end
|
|
521
542
|
end
|
|
522
543
|
|
|
523
544
|
exception || results
|
|
524
545
|
end
|
|
525
546
|
|
|
547
|
+
# ractors cannot execute blocks, so run the callback directly when not using ractors
|
|
548
|
+
def ractor_block(options)
|
|
549
|
+
klass, method_name = options[:ractor] ||
|
|
550
|
+
raise(ArgumentError, "pass the code you want to execute as `ractor: [ClassName, :method_name]`")
|
|
551
|
+
->(*args) { klass.send(method_name, *args) }
|
|
552
|
+
end
|
|
553
|
+
|
|
526
554
|
def ractor_build(use_port)
|
|
527
555
|
args = use_port ? [Ractor::Port.new] : []
|
|
528
556
|
ractor = Ractor.new(*args) do |port|
|
|
529
557
|
loop do
|
|
530
|
-
(klass, method_name), item, index = receive
|
|
558
|
+
(klass, method_name), item, index, with_index, discard_results = receive
|
|
531
559
|
break if index == :break
|
|
532
560
|
begin
|
|
533
|
-
|
|
561
|
+
value = with_index ? klass.send(method_name, item, index) : klass.send(method_name, item)
|
|
562
|
+
value = nil if discard_results
|
|
563
|
+
result = [nil, value, item, index]
|
|
534
564
|
rescue StandardError => e
|
|
535
565
|
result = [e, nil, item, index]
|
|
536
566
|
end
|
|
@@ -546,11 +576,19 @@ module Parallel
|
|
|
546
576
|
|
|
547
577
|
def ractor_result(item, index, result, results, results_mutex, options)
|
|
548
578
|
instrument_finish item, index, result, options
|
|
549
|
-
results_mutex.synchronize { results[index] =
|
|
579
|
+
results_mutex.synchronize { results[index] = result } unless options[:discard_results]
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
def ractor_send(ractor, callback, job, options)
|
|
583
|
+
item, index = job
|
|
584
|
+
instrument_start item, index, options
|
|
585
|
+
ractor.send [callback, item, index, options[:with_index], options[:discard_results]]
|
|
550
586
|
end
|
|
551
587
|
|
|
552
588
|
def ractor_stop(ractor)
|
|
553
589
|
ractor.send([[nil, nil], nil, :break])
|
|
590
|
+
rescue Ractor::ClosedError
|
|
591
|
+
nil
|
|
554
592
|
end
|
|
555
593
|
|
|
556
594
|
def work_in_processes(job_factory, options, &blk)
|
|
@@ -581,7 +619,8 @@ module Parallel
|
|
|
581
619
|
result = with_instrumentation item, index, options do
|
|
582
620
|
worker.work(job_factory.pack(item, index))
|
|
583
621
|
end
|
|
584
|
-
|
|
622
|
+
# arrays are not threads safe on jRuby
|
|
623
|
+
results_mutex.synchronize { results[index] = result } unless options[:discard_results]
|
|
585
624
|
rescue StandardError => e
|
|
586
625
|
exception = e
|
|
587
626
|
if exception.is_a?(Kill)
|
|
@@ -619,6 +658,13 @@ module Parallel
|
|
|
619
658
|
workers << worker(job_factory, options.merge(started_workers: workers, worker_number: i), &block)
|
|
620
659
|
end
|
|
621
660
|
workers
|
|
661
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
|
662
|
+
workers.each do |worker|
|
|
663
|
+
worker.stop
|
|
664
|
+
rescue StandardError
|
|
665
|
+
nil
|
|
666
|
+
end
|
|
667
|
+
raise
|
|
622
668
|
end
|
|
623
669
|
|
|
624
670
|
def worker(job_factory, options, &block)
|
|
@@ -646,6 +692,19 @@ module Parallel
|
|
|
646
692
|
child_write.close
|
|
647
693
|
|
|
648
694
|
Worker.new(parent_read, parent_write, pid, options[:serializer])
|
|
695
|
+
rescue Exception # rubocop:disable Lint/RescueException
|
|
696
|
+
[child_read, parent_write, parent_read, child_write].compact.each do |io|
|
|
697
|
+
io.close unless io.closed?
|
|
698
|
+
end
|
|
699
|
+
if pid
|
|
700
|
+
UserInterruptHandler.kill(pid)
|
|
701
|
+
begin
|
|
702
|
+
Process.wait(pid)
|
|
703
|
+
rescue Errno::ECHILD
|
|
704
|
+
nil
|
|
705
|
+
end
|
|
706
|
+
end
|
|
707
|
+
raise
|
|
649
708
|
end
|
|
650
709
|
|
|
651
710
|
def process_incoming_jobs(read, write, job_factory, options, &block)
|
|
@@ -687,10 +746,10 @@ module Parallel
|
|
|
687
746
|
args = [item]
|
|
688
747
|
args << index if options[:with_index]
|
|
689
748
|
results = block.call(*args)
|
|
690
|
-
if options[:
|
|
691
|
-
results
|
|
692
|
-
else
|
|
749
|
+
if options[:discard_results]
|
|
693
750
|
nil # avoid GC overhead of passing large results around
|
|
751
|
+
else
|
|
752
|
+
results
|
|
694
753
|
end
|
|
695
754
|
end
|
|
696
755
|
|
|
@@ -698,7 +757,7 @@ module Parallel
|
|
|
698
757
|
instrument_start(item, index, options)
|
|
699
758
|
result = yield
|
|
700
759
|
instrument_finish(item, index, result, options)
|
|
701
|
-
result unless options[:
|
|
760
|
+
result unless options[:discard_results]
|
|
702
761
|
end
|
|
703
762
|
|
|
704
763
|
def instrument_finish(item, index, result, options)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: parallel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Grosser
|
|
@@ -23,10 +23,10 @@ licenses:
|
|
|
23
23
|
- MIT
|
|
24
24
|
metadata:
|
|
25
25
|
bug_tracker_uri: https://github.com/grosser/parallel/issues
|
|
26
|
-
documentation_uri: https://github.com/grosser/parallel/blob/v2.
|
|
27
|
-
source_code_uri: https://github.com/grosser/parallel/tree/v2.
|
|
26
|
+
documentation_uri: https://github.com/grosser/parallel/blob/v2.2.0/Readme.md
|
|
27
|
+
source_code_uri: https://github.com/grosser/parallel/tree/v2.2.0
|
|
28
28
|
wiki_uri: https://github.com/grosser/parallel/wiki
|
|
29
|
-
changelog_uri: https://github.com/grosser/parallel/blob/v2.
|
|
29
|
+
changelog_uri: https://github.com/grosser/parallel/blob/v2.2.0/CHANGELOG.md
|
|
30
30
|
rubygems_mfa_required: 'true'
|
|
31
31
|
rdoc_options: []
|
|
32
32
|
require_paths:
|