concurrent_worker 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/concurrent_worker.rb +140 -133
- data/lib/concurrent_worker/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c743d7ebe52dcc21dcb90529e65d3cd0bbadf66a29dbbe16f8245f3c764cb787
|
4
|
+
data.tar.gz: f6d17a27e1b0666e896ebfeecf1b618ed2d2be87f5e9801899b3387ed4619469
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8843c5397cfd752204733a1b5f51f7fa9e924c5a7074ccb41b40f32320ef9a69680b16f1bd65dc9deec731f3ea155c3a8b832faf143499df9dc53525dfaf8d85
|
7
|
+
data.tar.gz: 979d6dd58b496f055a0647f8ff2a531e209c309d7475589998918c09e287b01b031bf0cabc16c7ba12e03dce91448ede61648469f0b55cf5fae8796fb3d6a811
|
data/Gemfile.lock
CHANGED
data/lib/concurrent_worker.rb
CHANGED
@@ -12,11 +12,11 @@ module ConcurrentWorker
|
|
12
12
|
def push(args)
|
13
13
|
@count.push(args)
|
14
14
|
end
|
15
|
-
|
16
15
|
def pop
|
17
16
|
@count.pop
|
18
17
|
@com.push([])
|
19
18
|
end
|
19
|
+
|
20
20
|
def wait(n)
|
21
21
|
return if @count.size <= n
|
22
22
|
while @com.pop
|
@@ -31,6 +31,10 @@ module ConcurrentWorker
|
|
31
31
|
@count.close
|
32
32
|
end
|
33
33
|
|
34
|
+
def closed?
|
35
|
+
@count.closed?
|
36
|
+
end
|
37
|
+
|
34
38
|
def rest
|
35
39
|
result = []
|
36
40
|
until @count.empty?
|
@@ -58,7 +62,17 @@ module ConcurrentWorker
|
|
58
62
|
# so that they can share instance variables:@xxxx.
|
59
63
|
#
|
60
64
|
|
61
|
-
attr_reader :req_counter, :
|
65
|
+
attr_reader :req_counter, :snd_queue_max
|
66
|
+
|
67
|
+
def queue_closed?
|
68
|
+
@req_counter.closed?
|
69
|
+
end
|
70
|
+
def queue_empty?
|
71
|
+
!queue_closed? && @req_counter.size == 0
|
72
|
+
end
|
73
|
+
def queue_available?
|
74
|
+
!queue_closed? && @req_counter.size < @snd_queue_max
|
75
|
+
end
|
62
76
|
|
63
77
|
def initialize(*args, **options, &work_block)
|
64
78
|
@args = args
|
@@ -69,13 +83,22 @@ module ConcurrentWorker
|
|
69
83
|
@result_callbacks = []
|
70
84
|
@retired_callbacks = []
|
71
85
|
|
72
|
-
@
|
86
|
+
@snd_queue_max = @options[:snd_queue_max] || 2
|
73
87
|
@req_counter = RequestCounter.new
|
74
|
-
|
75
|
-
|
76
|
-
|
88
|
+
|
89
|
+
case @options[:type]
|
90
|
+
when :process
|
91
|
+
class << self
|
92
|
+
include ConcurrentProcess
|
93
|
+
end
|
94
|
+
when :thread
|
95
|
+
class << self
|
96
|
+
include ConcurrentThread
|
97
|
+
end
|
77
98
|
else
|
78
|
-
|
99
|
+
class << self
|
100
|
+
include ConcurrentThread
|
101
|
+
end
|
79
102
|
end
|
80
103
|
end
|
81
104
|
|
@@ -88,6 +111,7 @@ module ConcurrentWorker
|
|
88
111
|
@result_callbacks.each do |callback|
|
89
112
|
callback.call(args)
|
90
113
|
end
|
114
|
+
@req_counter.pop
|
91
115
|
end
|
92
116
|
|
93
117
|
def add_retired_callback(&callback)
|
@@ -122,43 +146,55 @@ module ConcurrentWorker
|
|
122
146
|
end
|
123
147
|
end
|
124
148
|
end
|
125
|
-
|
126
|
-
def run
|
127
|
-
@state = :run
|
128
149
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
end
|
137
|
-
send_res(yield_work_block(args))
|
150
|
+
def set_default_loop_block
|
151
|
+
set_block(:loop_block) do
|
152
|
+
loop do
|
153
|
+
break if (req = receive_req).empty?
|
154
|
+
(args, work_block) = req
|
155
|
+
if work_block
|
156
|
+
set_block(:work_block, &work_block)
|
138
157
|
end
|
158
|
+
send_res(yield_work_block(args))
|
139
159
|
end
|
140
160
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
161
|
+
end
|
162
|
+
|
163
|
+
def set_default_base_block
|
164
|
+
set_block(:base_block) do
|
165
|
+
yield_loop_block
|
146
166
|
end
|
147
|
-
|
167
|
+
end
|
168
|
+
|
169
|
+
def run
|
170
|
+
@state = :run
|
171
|
+
set_default_loop_block unless @loop_block
|
172
|
+
set_default_base_block unless @base_block
|
148
173
|
cncr_block
|
149
174
|
end
|
150
|
-
|
151
175
|
|
152
176
|
def req(*args, &work_block)
|
153
177
|
unless @state == :run
|
154
178
|
run
|
155
179
|
end
|
156
|
-
@req_counter.wait(@
|
157
|
-
|
180
|
+
@req_counter.wait(@snd_queue_max)
|
181
|
+
begin
|
182
|
+
@req_counter.push([args, work_block])
|
183
|
+
send_req([args, work_block])
|
184
|
+
true
|
185
|
+
rescue ClosedQueueError, IOError
|
186
|
+
false
|
187
|
+
end
|
158
188
|
end
|
159
189
|
|
160
190
|
def quit
|
161
|
-
|
191
|
+
begin
|
192
|
+
@req_counter.push([])
|
193
|
+
send_req([])
|
194
|
+
true
|
195
|
+
rescue ClosedQueueError, IOError
|
196
|
+
false
|
197
|
+
end
|
162
198
|
end
|
163
199
|
|
164
200
|
def join
|
@@ -184,13 +220,7 @@ module ConcurrentWorker
|
|
184
220
|
end
|
185
221
|
|
186
222
|
def send_req(args)
|
187
|
-
|
188
|
-
@req_counter.push(args)
|
189
|
-
@thread_channel.push(args)
|
190
|
-
true
|
191
|
-
rescue ClosedQueueError
|
192
|
-
false
|
193
|
-
end
|
223
|
+
@thread_channel.push(args)
|
194
224
|
end
|
195
225
|
|
196
226
|
def receive_req
|
@@ -199,7 +229,6 @@ module ConcurrentWorker
|
|
199
229
|
|
200
230
|
def send_res(args)
|
201
231
|
call_result_callbacks(args)
|
202
|
-
@req_counter.pop
|
203
232
|
end
|
204
233
|
|
205
234
|
def wait_cncr_proc
|
@@ -245,24 +274,10 @@ module ConcurrentWorker
|
|
245
274
|
def close
|
246
275
|
[@wio, @rio].map(&:close)
|
247
276
|
end
|
248
|
-
|
249
277
|
end
|
250
|
-
|
251
|
-
def cncr_block
|
252
|
-
@ipc_channel = IPCDuplexChannel.new
|
253
|
-
@c_pid = fork do
|
254
|
-
@ipc_channel.choose_io
|
255
|
-
begin
|
256
|
-
yield_base_block
|
257
|
-
rescue
|
258
|
-
@ipc_channel.send($!)
|
259
|
-
ensure
|
260
|
-
@ipc_channel.send(:worker_loop_finished)
|
261
|
-
end
|
262
|
-
end
|
263
|
-
@ipc_channel.choose_io
|
264
278
|
|
265
|
-
|
279
|
+
def set_rcv_thread
|
280
|
+
Thread.new do
|
266
281
|
begin
|
267
282
|
loop do
|
268
283
|
result = @ipc_channel.recv
|
@@ -270,28 +285,37 @@ module ConcurrentWorker
|
|
270
285
|
raise result if result.kind_of?(Exception)
|
271
286
|
|
272
287
|
call_result_callbacks(result)
|
273
|
-
@req_counter.pop
|
274
288
|
end
|
275
289
|
rescue
|
276
290
|
Thread.pass
|
277
291
|
raise $!
|
278
292
|
ensure
|
279
|
-
@ipc_channel.close
|
280
293
|
@req_counter.close
|
294
|
+
@ipc_channel.close
|
281
295
|
call_retired_callbacks
|
282
296
|
end
|
283
297
|
end
|
284
298
|
end
|
299
|
+
|
300
|
+
def cncr_block
|
301
|
+
@ipc_channel = IPCDuplexChannel.new
|
302
|
+
@c_pid = fork do
|
303
|
+
@ipc_channel.choose_io
|
304
|
+
begin
|
305
|
+
yield_base_block
|
306
|
+
rescue
|
307
|
+
@ipc_channel.send($!)
|
308
|
+
ensure
|
309
|
+
@ipc_channel.send(:worker_loop_finished)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
@ipc_channel.choose_io
|
313
|
+
@rcv_thread = set_rcv_thread
|
314
|
+
end
|
285
315
|
|
286
316
|
def send_req(args)
|
287
|
-
|
288
|
-
|
289
|
-
@req_counter.push(args)
|
290
|
-
@ipc_channel.send(args)
|
291
|
-
true
|
292
|
-
rescue ClosedQueueError, IOError
|
293
|
-
false
|
294
|
-
end
|
317
|
+
#called from main process only
|
318
|
+
@ipc_channel.send(args)
|
295
319
|
end
|
296
320
|
|
297
321
|
def receive_req
|
@@ -309,86 +333,70 @@ module ConcurrentWorker
|
|
309
333
|
Process.waitpid(@c_pid)
|
310
334
|
rescue Errno::ECHILD
|
311
335
|
end
|
312
|
-
@
|
336
|
+
@rcv_thread && @rcv_thread.join
|
313
337
|
end
|
314
338
|
end
|
315
339
|
|
316
340
|
|
317
341
|
|
318
342
|
class WorkerPool < Array
|
319
|
-
def initialize(*args, **options, &work_block)
|
320
|
-
@args = args
|
321
|
-
|
322
|
-
@options = options
|
323
|
-
@max_num = @options[:pool_max] || 8
|
324
|
-
@set_blocks = []
|
325
|
-
if work_block
|
326
|
-
@set_blocks.push([:work_block, work_block])
|
327
|
-
end
|
328
343
|
|
329
|
-
|
330
|
-
@
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
loop do
|
336
|
-
break if (result = @callback_queue.pop).empty?
|
337
|
-
@result_callbacks.each do |callback|
|
338
|
-
callback.call(result[0])
|
339
|
-
end
|
340
|
-
@req_counter.pop
|
341
|
-
end
|
342
|
-
end
|
343
|
-
@req_queue_max = @options[:req_queue_max]||2
|
344
|
-
|
345
|
-
@req_queue = Queue.new
|
346
|
-
@req_counter = RequestCounter.new
|
347
|
-
@req_thread = Thread.new do
|
344
|
+
def need_new_worker?
|
345
|
+
self.size < @max_num && self.select{ |w| w.queue_empty? }.empty?
|
346
|
+
end
|
347
|
+
|
348
|
+
def set_snd_thread
|
349
|
+
Thread.new do
|
348
350
|
loop do
|
349
|
-
break if (req = @
|
350
|
-
|
351
|
-
w = nil
|
351
|
+
break if (req = @snd_queue.pop).empty?
|
352
352
|
loop do
|
353
|
+
delete_if{ |w| w.queue_closed? }
|
353
354
|
if need_new_worker?
|
354
|
-
|
355
|
-
|
356
|
-
@ready_queue.push(
|
355
|
+
w = deploy_worker
|
356
|
+
w.snd_queue_max.times do
|
357
|
+
@ready_queue.push(w)
|
357
358
|
end
|
358
359
|
end
|
359
|
-
break if
|
360
|
-
break if w.req(*req[0], &req[1])
|
360
|
+
break if @ready_queue.pop.req(*req[0], &req[1])
|
361
361
|
end
|
362
|
-
break if w.kind_of?(Array)
|
363
362
|
end
|
364
363
|
end
|
365
364
|
end
|
366
365
|
|
367
|
-
def
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
end
|
377
|
-
def shift
|
378
|
-
@array_mutex.synchronize do
|
379
|
-
super
|
380
|
-
end
|
381
|
-
end
|
382
|
-
def empty?
|
383
|
-
@array_mutex.synchronize do
|
384
|
-
super
|
366
|
+
def set_rcv_thread
|
367
|
+
Thread.new do
|
368
|
+
loop do
|
369
|
+
break if (result = @rcv_queue.pop).empty?
|
370
|
+
@result_callbacks.each do |callback|
|
371
|
+
callback.call(result[0])
|
372
|
+
end
|
373
|
+
@req_counter.pop
|
374
|
+
end
|
385
375
|
end
|
386
376
|
end
|
387
|
-
|
388
|
-
def
|
389
|
-
@
|
390
|
-
|
377
|
+
|
378
|
+
def initialize(*args, **options, &work_block)
|
379
|
+
@args = args
|
380
|
+
|
381
|
+
@options = options
|
382
|
+
@max_num = @options[:pool_max] || 8
|
383
|
+
@set_blocks = []
|
384
|
+
if work_block
|
385
|
+
@set_blocks.push([:work_block, work_block])
|
391
386
|
end
|
387
|
+
|
388
|
+
@ready_queue = Queue.new
|
389
|
+
|
390
|
+
@result_callbacks = []
|
391
|
+
|
392
|
+
@snd_queue_max = @options[:snd_queue_max]||2
|
393
|
+
@req_counter = RequestCounter.new
|
394
|
+
|
395
|
+
@snd_queue = Queue.new
|
396
|
+
@snd_thread = set_snd_thread
|
397
|
+
|
398
|
+
@rcv_queue = Queue.new
|
399
|
+
@rcv_thread = set_rcv_thread
|
392
400
|
end
|
393
401
|
|
394
402
|
def add_callback(&callback)
|
@@ -403,18 +411,17 @@ module ConcurrentWorker
|
|
403
411
|
|
404
412
|
|
405
413
|
def deploy_worker
|
406
|
-
w = Worker.new(*@args, type: @options[:type],
|
414
|
+
w = Worker.new(*@args, type: @options[:type], snd_queue_max: @snd_queue_max, &@work_block)
|
407
415
|
w.add_callback do |arg|
|
408
|
-
@
|
416
|
+
@rcv_queue.push([arg])
|
409
417
|
@ready_queue.push(w)
|
410
418
|
end
|
411
419
|
|
412
420
|
w.add_retired_callback do
|
413
421
|
w.req_counter.rest.each do
|
414
422
|
|req|
|
415
|
-
@
|
423
|
+
@snd_queue.push(req)
|
416
424
|
end
|
417
|
-
self.delete(w)
|
418
425
|
@ready_queue.push(w)
|
419
426
|
end
|
420
427
|
|
@@ -431,18 +438,18 @@ module ConcurrentWorker
|
|
431
438
|
end
|
432
439
|
|
433
440
|
def req(*args, &work_block)
|
434
|
-
@req_counter.wait(@max_num * @
|
441
|
+
@req_counter.wait(@max_num * @snd_queue_max)
|
435
442
|
@req_counter.push(true)
|
436
|
-
@
|
443
|
+
@snd_queue.push([args, work_block])
|
437
444
|
end
|
438
445
|
|
439
446
|
def join
|
440
447
|
@req_counter.wait(0)
|
441
448
|
self.shift.join until self.empty?
|
442
|
-
@
|
443
|
-
@
|
444
|
-
@
|
445
|
-
@
|
449
|
+
@rcv_queue.push([])
|
450
|
+
@rcv_thread.join
|
451
|
+
@snd_queue.push([])
|
452
|
+
@snd_thread.join
|
446
453
|
end
|
447
454
|
end
|
448
455
|
|