parallel 1.2.4 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f6ea4deb03b39b10b4efc968f86c86d8fba2c42f
4
- data.tar.gz: b32876b86f9acc449bb45d28b154708f9af0dee1
3
+ metadata.gz: d2df287a5ddf0d25ea8f7ab32b06e9d71046eef8
4
+ data.tar.gz: f4df68005a7a134922caa0dd7458a5ad48ebb14f
5
5
  SHA512:
6
- metadata.gz: 92021663b44c16d0ce0f9dfa0c616f3852f9e2a6f7c85521c06283f2fd5daad75f7dbf95703241c926b71eb98a44619eefdcc62d3039e4311d8ba4389fb06649
7
- data.tar.gz: c48fdaebf240f24722a41868688e0373349f78eb1de8e9329cdd0e458cdaf0458e1cbc6cbbfd4f3b5707c5363706e4755ed66c543332c03b39b2be909ccd0132
6
+ metadata.gz: 73b00704981e7a87f6c6448cc80759d4e4bbd62c07bc852c84c81da631480571f7acf1cff261eb72f3c2532cee96fb12670329ac9acf35c4f7c48272834ea875
7
+ data.tar.gz: e975280dc1eb0825479e03e2d433e89021ec336a4bc1ab3e05319afccf73d3c67f190938df1a3faeb5c9c8d1335a0ac64b67c9982c1e19936c34a83f120bdfc8
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,4 +1,3 @@
1
- require 'thread' # to get Thread.exclusive
2
1
  require 'rbconfig'
3
2
  require 'parallel/version'
4
3
  require 'parallel/processor_count'
@@ -15,6 +14,8 @@ module Parallel
15
14
  class Kill < StandardError
16
15
  end
17
16
 
17
+ Stop = Object.new
18
+
18
19
  INTERRUPT_SIGNAL = :SIGINT
19
20
 
20
21
  class ExceptionWrapper
@@ -47,9 +48,9 @@ module Parallel
47
48
  # process died
48
49
  end
49
50
 
50
- def work(index)
51
+ def work(data)
51
52
  begin
52
- Marshal.dump(index, write)
53
+ Marshal.dump(data, write)
53
54
  rescue Errno::EPIPE
54
55
  raise DeadWorker
55
56
  end
@@ -62,6 +63,66 @@ module Parallel
62
63
  end
63
64
  end
64
65
 
66
+ class ItemWrapper
67
+ def initialize(array, mutex)
68
+ @lambda = (array.respond_to?(:call) && array) || queue_wrapper(array)
69
+ @items = array.to_a unless @lambda # turn Range and other Enumerable-s into an Array
70
+ @mutex = mutex
71
+ @index = -1
72
+ end
73
+
74
+ def producer?
75
+ @lambda
76
+ end
77
+
78
+ def each_with_index(&block)
79
+ if producer?
80
+ loop do
81
+ item, index = self.next
82
+ break unless index
83
+ yield(item, index)
84
+ end
85
+ else
86
+ @items.each_with_index(&block)
87
+ end
88
+ end
89
+
90
+ def next
91
+ if producer?
92
+ # - index and item stay in sync
93
+ # - do not call lambda after it has returned Stop
94
+ item, index = @mutex.synchronize do
95
+ return if @stopped
96
+ item = @lambda.call
97
+ @stopped = (item == Parallel::Stop)
98
+ return if @stopped
99
+ [item, @index += 1]
100
+ end
101
+ else
102
+ index = @mutex.synchronize { @index += 1 }
103
+ return if index >= size
104
+ item = @items[index]
105
+ end
106
+ [item, index]
107
+ end
108
+
109
+ def size
110
+ @items.size
111
+ end
112
+
113
+ def pack(item, index)
114
+ producer? ? [item, index] : index
115
+ end
116
+
117
+ def unpack(data)
118
+ producer? ? data : [@items[data], data]
119
+ end
120
+
121
+ def queue_wrapper(array)
122
+ array.is_a?(::Queue) && lambda { array.pop(false) }
123
+ end
124
+ end
125
+
65
126
  class << self
66
127
  def in_threads(options={:count => 2})
67
128
  count, options = extract_count_from_options(options)
@@ -96,8 +157,7 @@ module Parallel
96
157
  end
97
158
 
98
159
  def map(array, options = {}, &block)
99
- array = array.to_a # turn Range and other Enumerable-s into an Array
100
- options[:mutex] ||= Mutex.new
160
+ options[:mutex] = Mutex.new
101
161
 
102
162
  if RUBY_PLATFORM =~ /java/ and not options[:in_processes]
103
163
  method = :in_threads
@@ -114,26 +174,36 @@ module Parallel
114
174
  size = 0
115
175
  end
116
176
  end
117
- size = [array.size, size].min
177
+
178
+ items = ItemWrapper.new(array, options[:mutex])
179
+
180
+ size = [items.producer? ? size : items.size, size].min
118
181
 
119
182
  options[:return_results] = (options[:preserve_results] != false || !!options[:finish])
120
- add_progress_bar!(array, options)
183
+ add_progress_bar!(items, options)
121
184
 
122
185
  if size == 0
123
- work_direct(array, options, &block)
186
+ work_direct(items, options, &block)
124
187
  elsif method == :in_threads
125
- work_in_threads(array, options.merge(:count => size), &block)
188
+ work_in_threads(items, options.merge(:count => size), &block)
126
189
  else
127
- work_in_processes(array, options.merge(:count => size), &block)
190
+ work_in_processes(items, options.merge(:count => size), &block)
128
191
  end
129
192
  end
130
193
 
131
- def add_progress_bar!(array, options)
194
+ def map_with_index(array, options={}, &block)
195
+ map(array, options.merge(:with_index => true), &block)
196
+ end
197
+
198
+ private
199
+
200
+ def add_progress_bar!(items, options)
132
201
  if title = options[:progress]
202
+ raise "Progressbar and producers don't mix" if items.producer?
133
203
  require 'ruby-progressbar'
134
204
  progress = ProgressBar.create(
135
205
  :title => title,
136
- :total => array.size,
206
+ :total => items.size,
137
207
  :format => '%t |%E | %B | %a'
138
208
  )
139
209
  old_finish = options[:finish]
@@ -144,15 +214,10 @@ module Parallel
144
214
  end
145
215
  end
146
216
 
147
- def map_with_index(array, options={}, &block)
148
- map(array, options.merge(:with_index => true), &block)
149
- end
150
-
151
- private
152
217
 
153
- def work_direct(array, options)
218
+ def work_direct(items, options)
154
219
  results = []
155
- array.each_with_index do |e,i|
220
+ items.each_with_index do |e,i|
156
221
  results << (options[:with_index] ? yield(e,i) : yield(e))
157
222
  end
158
223
  results
@@ -160,20 +225,18 @@ module Parallel
160
225
 
161
226
  def work_in_threads(items, options, &block)
162
227
  results = []
163
- current = -1
164
228
  exception = nil
165
229
 
166
230
  in_threads(options[:count]) do
167
231
  # as long as there are more items, work on one of them
168
232
  loop do
169
233
  break if exception
170
-
171
- index = Thread.exclusive { current += 1 }
172
- break if index >= items.size
234
+ item, index = items.next
235
+ break unless index
173
236
 
174
237
  begin
175
- results[index] = with_instrumentation items[index], index, options do
176
- call_with_index(items, index, options, &block)
238
+ results[index] = with_instrumentation item, index, options do
239
+ call_with_index(item, index, options, &block)
177
240
  end
178
241
  rescue StandardError => e
179
242
  exception = e
@@ -187,9 +250,9 @@ module Parallel
187
250
 
188
251
  def work_in_processes(items, options, &blk)
189
252
  workers = create_workers(items, options, &blk)
190
- current_index = -1
191
253
  results = []
192
254
  exception = nil
255
+
193
256
  kill_on_ctrl_c(workers.map(&:pid)) do
194
257
  in_threads(options[:count]) do |i|
195
258
  worker = workers[i]
@@ -198,11 +261,11 @@ module Parallel
198
261
  begin
199
262
  loop do
200
263
  break if exception
201
- index = Thread.exclusive{ current_index += 1 }
202
- break if index >= items.size
264
+ item, index = items.next
265
+ break unless index
203
266
 
204
- output = with_instrumentation items[index], index, options do
205
- worker.work(index)
267
+ output = with_instrumentation item, index, options do
268
+ worker.work(items.pack(item, index))
206
269
  end
207
270
 
208
271
  if ExceptionWrapper === output
@@ -264,9 +327,10 @@ module Parallel
264
327
 
265
328
  def process_incoming_jobs(read, write, items, options, &block)
266
329
  while !read.eof?
267
- index = Marshal.load(read)
330
+ data = Marshal.load(read)
331
+ item, index = items.unpack(data)
268
332
  result = begin
269
- call_with_index(items, index, options, &block)
333
+ call_with_index(item, index, options, &block)
270
334
  rescue StandardError => e
271
335
  ExceptionWrapper.new(e)
272
336
  end
@@ -355,8 +419,8 @@ module Parallel
355
419
  end
356
420
  end
357
421
 
358
- def call_with_index(array, index, options, &block)
359
- args = [array[index]]
422
+ def call_with_index(item, index, options, &block)
423
+ args = [item]
360
424
  args << index if options[:with_index]
361
425
  if options[:return_results]
362
426
  block.call(*args)
@@ -1,3 +1,3 @@
1
1
  module Parallel
2
- VERSION = Version = '1.2.4'
2
+ VERSION = Version = '1.3.0'
3
3
  end
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: 1.2.4
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
@@ -30,7 +30,7 @@ cert_chain:
30
30
  F5etKHZg0j3eHO31/i2HnswY04lqGImUu6aM5EnijFTB7PPW2KwKKM4+kKDYFdlw
31
31
  /0WV1Ng2/Y6qsHwmqGg2VlYj2h4=
32
32
  -----END CERTIFICATE-----
33
- date: 2014-08-17 00:00:00.000000000 Z
33
+ date: 2014-08-30 00:00:00.000000000 Z
34
34
  dependencies: []
35
35
  description:
36
36
  email: michael@grosser.it
metadata.gz.sig CHANGED
Binary file