in_threads 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/.rubocop.yml +53 -0
- data/.travis.yml +11 -1
- data/Gemfile +1 -1
- data/README.markdown +6 -2
- data/in_threads.gemspec +4 -1
- data/lib/in_threads.rb +153 -44
- data/spec/in_threads_spec.rb +277 -202
- data/spec/spec_helper.rb +0 -0
- metadata +22 -9
- data/lib/in_threads/enumerable.rb +0 -26
- data/lib/in_threads/filler.rb +0 -54
- data/lib/in_threads/thread_limiter.rb +0 -41
data/spec/in_threads_spec.rb
CHANGED
@@ -1,29 +1,38 @@
|
|
1
|
-
|
2
|
-
require 'rspec'
|
1
|
+
require 'spec_helper'
|
3
2
|
require 'in_threads'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
# Test item with value
|
5
|
+
class ValueItem
|
6
|
+
# Use fast_check? for matching
|
7
|
+
module FastCheckMatcher
|
8
|
+
def self.===(item)
|
9
|
+
unless item.respond_to?(:fast_check?)
|
10
|
+
fail "#{item.inspect} doesn't respont to fast_check?"
|
11
|
+
end
|
12
|
+
item.fast_check?
|
13
|
+
end
|
8
14
|
end
|
9
15
|
|
10
|
-
def
|
11
|
-
|
16
|
+
def initialize(i, value)
|
17
|
+
@i, @value = i, value
|
12
18
|
end
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
raise "#{item.inspect} is not an Item" unless item.is_a?(Item)
|
17
|
-
(0.25..0.75) === item.instance_variable_get(:@value)
|
18
|
-
end
|
20
|
+
def ==(other)
|
21
|
+
id == other.id
|
19
22
|
end
|
20
23
|
|
21
24
|
def value
|
22
|
-
sleep
|
25
|
+
sleep
|
26
|
+
@value
|
23
27
|
end
|
24
28
|
|
25
29
|
def check?
|
26
|
-
|
30
|
+
sleep
|
31
|
+
fast_check?
|
32
|
+
end
|
33
|
+
|
34
|
+
def fast_check?
|
35
|
+
!!@value
|
27
36
|
end
|
28
37
|
|
29
38
|
def touch_n_value(*args)
|
@@ -47,35 +56,48 @@ private
|
|
47
56
|
end
|
48
57
|
end
|
49
58
|
|
50
|
-
|
51
|
-
|
52
|
-
|
59
|
+
# Test item with random value
|
60
|
+
class RandItem < ValueItem
|
61
|
+
def initialize(i)
|
62
|
+
super(i, Kernel.rand)
|
53
63
|
end
|
54
64
|
|
55
|
-
def
|
56
|
-
|
65
|
+
def fast_check?
|
66
|
+
@value < 0.5
|
57
67
|
end
|
68
|
+
end
|
58
69
|
|
59
|
-
|
60
|
-
|
70
|
+
# Create custom Enumerables
|
71
|
+
module CustomEnum
|
72
|
+
def self.new(&block)
|
73
|
+
Class.new do
|
74
|
+
include Enumerable
|
75
|
+
define_method :each, &block
|
76
|
+
end.new
|
61
77
|
end
|
62
78
|
end
|
63
79
|
|
80
|
+
class TestException < StandardError; end
|
81
|
+
|
64
82
|
def describe_enum_method(method, &block)
|
65
83
|
@enum_methods ||= Enumerable.instance_methods.map(&:to_s)
|
66
84
|
if @enum_methods.include?(method)
|
67
85
|
describe(method, &block)
|
68
86
|
else
|
69
|
-
it
|
70
|
-
exception_regexp =
|
71
|
-
|
87
|
+
it 'should not be defined' do
|
88
|
+
exception_regexp =
|
89
|
+
/^undefined method `#{Regexp.escape(method)}' .*\bInThreads\b/
|
90
|
+
expect{ enum.in_threads.send(method) }.
|
91
|
+
to raise_error(NoMethodError, exception_regexp)
|
72
92
|
end
|
73
93
|
end
|
74
94
|
end
|
75
95
|
|
76
|
-
describe
|
77
|
-
let(:enum){ 30.times.map{ |i|
|
78
|
-
|
96
|
+
describe 'in_threads' do
|
97
|
+
let(:enum){ 30.times.map{ |i| RandItem.new(i) } }
|
98
|
+
|
99
|
+
# small coefficient, should be more if sleep time coefficient is bigger
|
100
|
+
let(:speed_coef){ 0.666 }
|
79
101
|
|
80
102
|
def measure
|
81
103
|
start = Time.now
|
@@ -83,34 +105,35 @@ describe "in_threads" do
|
|
83
105
|
Time.now - start
|
84
106
|
end
|
85
107
|
|
86
|
-
describe
|
87
|
-
describe
|
88
|
-
it
|
108
|
+
describe 'consistency' do
|
109
|
+
describe 'verifying params' do
|
110
|
+
it 'should complain about using with non enumerable' do
|
89
111
|
expect{ InThreads.new(1) }.to raise_error(ArgumentError)
|
90
112
|
end
|
91
113
|
|
92
114
|
[1..10, 10.times, {}, []].each do |o|
|
93
|
-
it "should complain about using with #{o.class}" do
|
115
|
+
it "should not complain about using with #{o.class}" do
|
94
116
|
expect{ InThreads.new(o) }.not_to raise_error
|
95
117
|
end
|
96
118
|
end
|
97
119
|
|
98
|
-
it
|
120
|
+
it 'should complain about using less than 2 threads' do
|
99
121
|
expect{ 10.times.in_threads(1) }.to raise_error(ArgumentError)
|
100
122
|
end
|
101
123
|
|
102
|
-
it
|
124
|
+
it 'should not complain about using 2 or more threads' do
|
103
125
|
expect{ 10.times.in_threads(2) }.not_to raise_error
|
104
126
|
end
|
105
127
|
end
|
106
128
|
|
107
|
-
describe
|
108
|
-
it
|
129
|
+
describe 'in_threads method' do
|
130
|
+
it 'should not change existing instance' do
|
109
131
|
threaded = enum.in_threads(10)
|
110
132
|
expect{ threaded.in_threads(20) }.not_to change(threaded, :thread_count)
|
111
133
|
end
|
112
134
|
|
113
|
-
it
|
135
|
+
it 'should create new instance with different title when called on '\
|
136
|
+
'WithProgress' do
|
114
137
|
threaded = enum.in_threads(10)
|
115
138
|
tthreaded = threaded.in_threads(20)
|
116
139
|
expect(threaded.thread_count).to eq(10)
|
@@ -121,7 +144,7 @@ describe "in_threads" do
|
|
121
144
|
end
|
122
145
|
end
|
123
146
|
|
124
|
-
describe
|
147
|
+
describe 'thread count' do
|
125
148
|
let(:enum){ 100.times.map{ |i| ValueItem.new(i, i < 50) } }
|
126
149
|
|
127
150
|
%w[each map all?].each do |method|
|
@@ -146,104 +169,113 @@ describe "in_threads" do
|
|
146
169
|
end
|
147
170
|
end
|
148
171
|
|
149
|
-
describe
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
yield ValueItem.new(i, i < 50)
|
172
|
+
describe 'underlying enumerable usage' do
|
173
|
+
%w[each map all?].each do |method|
|
174
|
+
it "should call underlying enumerable.each only once for #{method}" do
|
175
|
+
enum = CustomEnum.new do |&block|
|
176
|
+
100.times.each do |i|
|
177
|
+
block[ValueItem.new(i, i < 50)]
|
178
|
+
end
|
157
179
|
end
|
180
|
+
|
181
|
+
expect(enum).to receive(:each).once.and_call_original
|
182
|
+
enum.in_threads(13).send(method, &:check?)
|
158
183
|
end
|
159
184
|
end
|
160
|
-
let(:enum){ CheckEachCalls.new }
|
161
185
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
186
|
+
it 'should not yield all elements when not needed' do
|
187
|
+
enum = CustomEnum.new do |&block|
|
188
|
+
100.times{ block[1] }
|
189
|
+
fail
|
166
190
|
end
|
191
|
+
|
192
|
+
enum.in_threads(13).all?{ false }
|
167
193
|
end
|
168
194
|
end
|
169
195
|
end
|
170
196
|
|
171
|
-
describe
|
172
|
-
|
197
|
+
describe 'methods' do
|
198
|
+
enumerable_methods = Enumerable.instance_methods
|
199
|
+
in_threads_methods = 10.times.in_threads.class.instance_methods
|
200
|
+
(enumerable_methods - in_threads_methods).each do |method|
|
173
201
|
pending method
|
174
202
|
end
|
175
203
|
|
176
|
-
class TestException < StandardError; end
|
177
|
-
|
178
204
|
def check_test_exception(enum, &block)
|
179
205
|
expect{ block[enum.in_threads] }.to raise_exception(TestException)
|
180
206
|
expect{ block[enum.in_threads(1000)] }.to raise_exception(TestException)
|
181
207
|
end
|
182
208
|
|
183
|
-
describe
|
184
|
-
it
|
209
|
+
describe 'each' do
|
210
|
+
it 'should return same enum after running' do
|
185
211
|
expect(enum.in_threads.each(&:value)).to eq(enum)
|
186
212
|
end
|
187
213
|
|
188
|
-
it
|
214
|
+
it 'should execute block for each element' do
|
189
215
|
enum.each{ |o| expect(o).to receive(:touch).once }
|
190
216
|
enum.in_threads.each(&:touch_n_value)
|
191
217
|
end
|
192
218
|
|
193
|
-
it
|
194
|
-
expect(measure{ enum.in_threads.each(&:value) }).
|
219
|
+
it 'should run faster with threads' do
|
220
|
+
expect(measure{ enum.in_threads.each(&:value) }).
|
221
|
+
to be < measure{ enum.each(&:value) } * speed_coef
|
195
222
|
end
|
196
223
|
|
197
|
-
it
|
198
|
-
expect(measure{ enum.in_threads(10).each(&:value) }).
|
224
|
+
it 'should run faster with more threads' do
|
225
|
+
expect(measure{ enum.in_threads(10).each(&:value) }).
|
226
|
+
to be < measure{ enum.in_threads(2).each(&:value) } * speed_coef
|
199
227
|
end
|
200
228
|
|
201
|
-
it
|
229
|
+
it 'should return same enum without block' do
|
202
230
|
expect(enum.in_threads.each.to_a).to eq(enum.each.to_a)
|
203
231
|
end
|
204
232
|
|
205
|
-
it
|
233
|
+
it 'should raise exception in outer thread' do
|
206
234
|
check_test_exception(enum) do |threaded|
|
207
|
-
threaded.each{
|
235
|
+
threaded.each{ fail TestException }
|
208
236
|
end
|
209
237
|
end
|
210
238
|
end
|
211
239
|
|
212
240
|
%w[each_with_index enum_with_index].each do |method|
|
213
241
|
describe_enum_method method do
|
214
|
-
let(:runner){ proc{ |o,
|
242
|
+
let(:runner){ proc{ |o, _i| o.value } }
|
215
243
|
|
216
|
-
it
|
217
|
-
expect(enum.in_threads.send(method, &runner)).
|
244
|
+
it 'should return same result with threads' do
|
245
|
+
expect(enum.in_threads.send(method, &runner)).
|
246
|
+
to eq(enum.send(method, &runner))
|
218
247
|
end
|
219
248
|
|
220
|
-
it
|
249
|
+
it 'should fire same objects' do
|
221
250
|
enum.send(method){ |o, i| expect(o).to receive(:touch).with(i).once }
|
222
251
|
enum.in_threads.send(method){ |o, i| o.touch_n_value(i) }
|
223
252
|
end
|
224
253
|
|
225
|
-
it
|
226
|
-
expect(measure{ enum.in_threads.send(method, &runner) }).
|
254
|
+
it 'should run faster with threads' do
|
255
|
+
expect(measure{ enum.in_threads.send(method, &runner) }).
|
256
|
+
to be < measure{ enum.send(method, &runner) } * speed_coef
|
227
257
|
end
|
228
258
|
|
229
|
-
it
|
230
|
-
expect(enum.in_threads.send(method).to_a).
|
259
|
+
it 'should return same enum without block' do
|
260
|
+
expect(enum.in_threads.send(method).to_a).
|
261
|
+
to eq(enum.send(method).to_a)
|
231
262
|
end
|
232
263
|
|
233
|
-
it
|
264
|
+
it 'should raise exception in outer thread' do
|
234
265
|
check_test_exception(enum) do |threaded|
|
235
|
-
threaded.send(method){
|
266
|
+
threaded.send(method){ fail TestException }
|
236
267
|
end
|
237
268
|
end
|
238
269
|
end
|
239
270
|
end
|
240
271
|
|
241
|
-
describe
|
242
|
-
it
|
243
|
-
expect(enum.in_threads.reverse_each(&:value)).
|
272
|
+
describe 'reverse_each' do
|
273
|
+
it 'should return same result with threads' do
|
274
|
+
expect(enum.in_threads.reverse_each(&:value)).
|
275
|
+
to eq(enum.reverse_each(&:value))
|
244
276
|
end
|
245
277
|
|
246
|
-
it
|
278
|
+
it 'should fire same objects in reverse order' do
|
247
279
|
@order = double('order', :notify => nil)
|
248
280
|
expect(@order).to receive(:notify).with(enum.last).ordered
|
249
281
|
expect(@order).to receive(:notify).with(enum[enum.length / 2]).ordered
|
@@ -256,17 +288,18 @@ describe "in_threads" do
|
|
256
288
|
end
|
257
289
|
end
|
258
290
|
|
259
|
-
it
|
260
|
-
expect(measure{ enum.in_threads.reverse_each(&:value) }).
|
291
|
+
it 'should run faster with threads' do
|
292
|
+
expect(measure{ enum.in_threads.reverse_each(&:value) }).
|
293
|
+
to be < measure{ enum.reverse_each(&:value) } * speed_coef
|
261
294
|
end
|
262
295
|
|
263
|
-
it
|
296
|
+
it 'should return same enum without block' do
|
264
297
|
expect(enum.in_threads.reverse_each.to_a).to eq(enum.reverse_each.to_a)
|
265
298
|
end
|
266
299
|
|
267
|
-
it
|
300
|
+
it 'should raise exception in outer thread' do
|
268
301
|
check_test_exception(enum) do |threaded|
|
269
|
-
threaded.reverse_each{
|
302
|
+
threaded.reverse_each{ fail TestException }
|
270
303
|
end
|
271
304
|
end
|
272
305
|
end
|
@@ -276,13 +309,14 @@ describe "in_threads" do
|
|
276
309
|
detect find find_index drop_while take_while
|
277
310
|
].each do |method|
|
278
311
|
describe method do
|
279
|
-
let(:enum){ 100.times.map{ |i| ValueItem.new(i, i
|
312
|
+
let(:enum){ 100.times.map{ |i| ValueItem.new(i, i.odd?) } }
|
280
313
|
|
281
|
-
it
|
282
|
-
expect(enum.in_threads.send(method, &:check?)).
|
314
|
+
it 'should return same result with threads' do
|
315
|
+
expect(enum.in_threads.send(method, &:check?)).
|
316
|
+
to eq(enum.send(method, &:check?))
|
283
317
|
end
|
284
318
|
|
285
|
-
it
|
319
|
+
it 'should fire same objects but not all' do
|
286
320
|
a = []
|
287
321
|
enum.send(method) do |o|
|
288
322
|
a << o
|
@@ -291,21 +325,25 @@ describe "in_threads" do
|
|
291
325
|
|
292
326
|
@a = []
|
293
327
|
@mutex = Mutex.new
|
294
|
-
enum.in_threads.send(method)
|
328
|
+
enum.in_threads.send(method) do |o|
|
329
|
+
@mutex.synchronize{ @a << o }
|
330
|
+
o.check?
|
331
|
+
end
|
295
332
|
|
296
333
|
expect(@a.length).to be >= a.length
|
297
334
|
expect(@a.length).to be <= enum.length * 0.5
|
298
335
|
end
|
299
336
|
|
300
|
-
it
|
337
|
+
it 'should run faster with threads' do
|
301
338
|
boolean = %w[all? drop_while take_while].include?(method)
|
302
339
|
enum = 30.times.map{ |i| ValueItem.new(i, boolean) }
|
303
|
-
expect(measure{ enum.in_threads.send(method, &:check?) }).
|
340
|
+
expect(measure{ enum.in_threads.send(method, &:check?) }).
|
341
|
+
to be < measure{ enum.send(method, &:check?) } * speed_coef
|
304
342
|
end
|
305
343
|
|
306
|
-
it
|
344
|
+
it 'should raise exception in outer thread' do
|
307
345
|
check_test_exception(enum) do |threaded|
|
308
|
-
threaded.send(method){
|
346
|
+
threaded.send(method){ fail TestException }
|
309
347
|
end
|
310
348
|
end
|
311
349
|
end
|
@@ -313,22 +351,24 @@ describe "in_threads" do
|
|
313
351
|
|
314
352
|
%w[partition find_all select reject count].each do |method|
|
315
353
|
describe method do
|
316
|
-
it
|
317
|
-
expect(enum.in_threads.send(method, &:check?)).
|
354
|
+
it 'should return same result with threads' do
|
355
|
+
expect(enum.in_threads.send(method, &:check?)).
|
356
|
+
to eq(enum.send(method, &:check?))
|
318
357
|
end
|
319
358
|
|
320
|
-
it
|
359
|
+
it 'should fire same objects' do
|
321
360
|
enum.send(method){ |o| expect(o).to receive(:touch).once }
|
322
361
|
enum.in_threads.send(method, &:touch_n_check?)
|
323
362
|
end
|
324
363
|
|
325
|
-
it
|
326
|
-
expect(measure{ enum.in_threads.send(method, &:check?) }).
|
364
|
+
it 'should run faster with threads' do
|
365
|
+
expect(measure{ enum.in_threads.send(method, &:check?) }).
|
366
|
+
to be < measure{ enum.send(method, &:check?) } * speed_coef
|
327
367
|
end
|
328
368
|
|
329
|
-
it
|
369
|
+
it 'should raise exception in outer thread' do
|
330
370
|
check_test_exception(enum) do |threaded|
|
331
|
-
threaded.send(method){
|
371
|
+
threaded.send(method){ fail TestException }
|
332
372
|
end
|
333
373
|
end
|
334
374
|
end
|
@@ -336,22 +376,24 @@ describe "in_threads" do
|
|
336
376
|
|
337
377
|
%w[collect map group_by max_by min_by minmax_by sort_by].each do |method|
|
338
378
|
describe method do
|
339
|
-
it
|
340
|
-
expect(enum.in_threads.send(method, &:value)).
|
379
|
+
it 'should return same result with threads' do
|
380
|
+
expect(enum.in_threads.send(method, &:value)).
|
381
|
+
to eq(enum.send(method, &:value))
|
341
382
|
end
|
342
383
|
|
343
|
-
it
|
384
|
+
it 'should fire same objects' do
|
344
385
|
enum.send(method){ |o| expect(o).to receive(:touch).once; 0 }
|
345
386
|
enum.in_threads.send(method, &:touch_n_value)
|
346
387
|
end
|
347
388
|
|
348
|
-
it
|
349
|
-
expect(measure{ enum.in_threads.send(method, &:value) }).
|
389
|
+
it 'should run faster with threads' do
|
390
|
+
expect(measure{ enum.in_threads.send(method, &:value) }).
|
391
|
+
to be < measure{ enum.send(method, &:value) } * speed_coef
|
350
392
|
end
|
351
393
|
|
352
|
-
it
|
394
|
+
it 'should raise exception in outer thread' do
|
353
395
|
check_test_exception(enum) do |threaded|
|
354
|
-
threaded.send(method){
|
396
|
+
threaded.send(method){ fail TestException }
|
355
397
|
end
|
356
398
|
end
|
357
399
|
end
|
@@ -361,191 +403,220 @@ describe "in_threads" do
|
|
361
403
|
describe_enum_method method do
|
362
404
|
let(:runner){ proc{ |a| a.each(&:value) } }
|
363
405
|
|
364
|
-
it
|
365
|
-
enum.send(method, 3)
|
406
|
+
it 'should fire same objects' do
|
407
|
+
enum.send(method, 3) do |a|
|
408
|
+
expect(a.first).to receive(:touch).with(a).once
|
409
|
+
end
|
366
410
|
enum.in_threads.send(method, 3){ |a| a.first.touch_n_value(a) }
|
367
411
|
end
|
368
412
|
|
369
|
-
it
|
370
|
-
expect(enum.in_threads.send(method, 3, &runner)).
|
413
|
+
it 'should return same with block' do
|
414
|
+
expect(enum.in_threads.send(method, 3, &runner)).
|
415
|
+
to eq(enum.send(method, 3, &runner))
|
371
416
|
end
|
372
417
|
|
373
|
-
it
|
374
|
-
expect(measure{ enum.in_threads.send(method, 3, &runner) }).
|
418
|
+
it 'should run faster with threads' do
|
419
|
+
expect(measure{ enum.in_threads.send(method, 3, &runner) }).
|
420
|
+
to be < measure{ enum.send(method, 3, &runner) } * speed_coef
|
375
421
|
end
|
376
422
|
|
377
|
-
it
|
378
|
-
expect(enum.in_threads.send(method, 3).to_a).
|
423
|
+
it 'should return same without block' do
|
424
|
+
expect(enum.in_threads.send(method, 3).to_a).
|
425
|
+
to eq(enum.send(method, 3).to_a)
|
379
426
|
end
|
380
427
|
|
381
|
-
it
|
428
|
+
it 'should raise exception in outer thread' do
|
382
429
|
check_test_exception(enum) do |threaded|
|
383
|
-
threaded.send(method, 3){
|
430
|
+
threaded.send(method, 3){ fail TestException }
|
384
431
|
end
|
385
432
|
end
|
386
433
|
end
|
387
434
|
end
|
388
435
|
|
389
|
-
describe
|
436
|
+
describe 'zip' do
|
390
437
|
let(:runner){ proc{ |a| a.each(&:value) } }
|
391
438
|
|
392
|
-
it
|
393
|
-
enum.zip(enum, enum)
|
394
|
-
|
439
|
+
it 'should fire same objects' do
|
440
|
+
enum.zip(enum, enum) do |a|
|
441
|
+
expect(a.first).to receive(:touch).with(a).once
|
442
|
+
end
|
443
|
+
|
444
|
+
enum.in_threads.zip(enum, enum) do |a|
|
445
|
+
a.first.touch_n_value(a)
|
446
|
+
end
|
395
447
|
end
|
396
448
|
|
397
|
-
it
|
398
|
-
expect(enum.in_threads.zip(enum, enum, &runner)).
|
449
|
+
it 'should return same with block' do
|
450
|
+
expect(enum.in_threads.zip(enum, enum, &runner)).
|
451
|
+
to eq(enum.zip(enum, enum, &runner))
|
399
452
|
end
|
400
453
|
|
401
|
-
it
|
402
|
-
expect(measure{ enum.in_threads.zip(enum, enum, &runner) }).
|
454
|
+
it 'should run faster with threads' do
|
455
|
+
expect(measure{ enum.in_threads.zip(enum, enum, &runner) }).
|
456
|
+
to be < measure{ enum.zip(enum, enum, &runner) } * speed_coef
|
403
457
|
end
|
404
458
|
|
405
|
-
it
|
459
|
+
it 'should return same without block' do
|
406
460
|
expect(enum.in_threads.zip(enum, enum)).to eq(enum.zip(enum, enum))
|
407
461
|
end
|
408
462
|
|
409
|
-
it
|
463
|
+
it 'should raise exception in outer thread' do
|
410
464
|
check_test_exception(enum) do |threaded|
|
411
|
-
threaded.zip(enum, enum){
|
465
|
+
threaded.zip(enum, enum){ fail TestException }
|
412
466
|
end
|
413
467
|
end
|
414
468
|
end
|
415
469
|
|
416
|
-
describe
|
417
|
-
it
|
470
|
+
describe 'cycle' do
|
471
|
+
it 'should fire same objects' do
|
418
472
|
enum.cycle(1){ |o| expect(o).to receive(:touch).exactly(3).times }
|
419
473
|
enum.in_threads.cycle(3, &:touch_n_value)
|
420
474
|
end
|
421
475
|
|
422
|
-
it
|
423
|
-
expect(measure{ enum.in_threads.cycle(3, &:value) }).
|
476
|
+
it 'should run faster with threads' do
|
477
|
+
expect(measure{ enum.in_threads.cycle(3, &:value) }).
|
478
|
+
to be < measure{ enum.cycle(3, &:value) } * speed_coef
|
424
479
|
end
|
425
480
|
|
426
|
-
it
|
481
|
+
it 'should return same enum without block' do
|
427
482
|
expect(enum.in_threads.cycle(3).to_a).to eq(enum.cycle(3).to_a)
|
428
483
|
end
|
429
484
|
|
430
|
-
it
|
485
|
+
it 'should raise exception in outer thread' do
|
431
486
|
check_test_exception(enum) do |threaded|
|
432
|
-
threaded.cycle{
|
487
|
+
threaded.cycle{ fail TestException }
|
433
488
|
end
|
434
489
|
end
|
435
490
|
end
|
436
491
|
|
437
|
-
describe
|
438
|
-
let(:matcher){
|
492
|
+
describe 'grep' do
|
493
|
+
let(:matcher){ ValueItem::FastCheckMatcher }
|
439
494
|
|
440
|
-
it
|
441
|
-
enum.each
|
495
|
+
it 'should fire same objects' do
|
496
|
+
enum.each do |o|
|
497
|
+
expect(o).to receive(:touch).exactly(o.fast_check? ? 1 : 0).times
|
498
|
+
end
|
442
499
|
enum.in_threads.grep(matcher, &:touch_n_value)
|
443
500
|
end
|
444
501
|
|
445
|
-
it
|
446
|
-
expect(enum.in_threads.grep(matcher, &:value)).
|
502
|
+
it 'should return same with block' do
|
503
|
+
expect(enum.in_threads.grep(matcher, &:value)).
|
504
|
+
to eq(enum.grep(matcher, &:value))
|
447
505
|
end
|
448
506
|
|
449
|
-
it
|
450
|
-
expect(measure{ enum.in_threads.grep(matcher, &:value) }).
|
507
|
+
it 'should run faster with threads' do
|
508
|
+
expect(measure{ enum.in_threads.grep(matcher, &:value) }).
|
509
|
+
to be < measure{ enum.grep(matcher, &:value) } * speed_coef
|
451
510
|
end
|
452
511
|
|
453
|
-
it
|
512
|
+
it 'should return same without block' do
|
454
513
|
expect(enum.in_threads.grep(matcher)).to eq(enum.grep(matcher))
|
455
514
|
end
|
456
515
|
|
457
|
-
it
|
516
|
+
it 'should raise exception in outer thread' do
|
458
517
|
check_test_exception(enum) do |threaded|
|
459
|
-
threaded.grep(matcher){
|
518
|
+
threaded.grep(matcher){ fail TestException }
|
460
519
|
end
|
461
520
|
end
|
462
521
|
end
|
463
522
|
|
464
|
-
describe_enum_method
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
10.times{
|
469
|
-
10.times{
|
470
|
-
10.times{ yield 4, 5, 6 }
|
523
|
+
describe_enum_method 'each_entry' do
|
524
|
+
let(:enum) do
|
525
|
+
CustomEnum.new do |&block|
|
526
|
+
10.times{ block[1] }
|
527
|
+
10.times{ block[2, 3] }
|
528
|
+
10.times{ block[4, 5, 6] }
|
471
529
|
end
|
472
530
|
end
|
473
|
-
|
474
|
-
let(:enum){ EachEntryYielder.new }
|
475
531
|
let(:runner){ proc{ |o| ValueItem.new(0, o).value } }
|
476
532
|
|
477
|
-
it
|
478
|
-
expect(enum.in_threads.each_entry(&runner)).
|
533
|
+
it 'should return same result with threads' do
|
534
|
+
expect(enum.in_threads.each_entry(&runner)).
|
535
|
+
to eq(enum.each_entry(&runner))
|
479
536
|
end
|
480
537
|
|
481
|
-
it
|
482
|
-
@
|
483
|
-
expect(@
|
484
|
-
expect(@
|
485
|
-
expect(@
|
538
|
+
it 'should execute block for each element' do
|
539
|
+
@o = double('order')
|
540
|
+
expect(@o).to receive(:notify).with(1).exactly(10).times.ordered
|
541
|
+
expect(@o).to receive(:notify).with([2, 3]).exactly(10).times.ordered
|
542
|
+
expect(@o).to receive(:notify).with([4, 5, 6]).exactly(10).times.ordered
|
486
543
|
@mutex = Mutex.new
|
487
544
|
enum.in_threads.each_entry do |o|
|
488
|
-
@mutex.synchronize{ @
|
545
|
+
@mutex.synchronize{ @o.notify(o) }
|
489
546
|
runner[]
|
490
547
|
end
|
491
548
|
end
|
492
549
|
|
493
|
-
it
|
494
|
-
expect(measure{ enum.in_threads.each_entry(&runner) }).
|
550
|
+
it 'should run faster with threads' do
|
551
|
+
expect(measure{ enum.in_threads.each_entry(&runner) }).
|
552
|
+
to be < measure{ enum.each_entry(&runner) } * speed_coef
|
495
553
|
end
|
496
554
|
|
497
|
-
it
|
555
|
+
it 'should return same enum without block' do
|
498
556
|
expect(enum.in_threads.each_entry.to_a).to eq(enum.each_entry.to_a)
|
499
557
|
end
|
500
558
|
|
501
|
-
it
|
559
|
+
it 'should raise exception in outer thread' do
|
502
560
|
check_test_exception(enum) do |threaded|
|
503
|
-
threaded.each_entry{
|
561
|
+
threaded.each_entry{ fail TestException }
|
504
562
|
end
|
505
563
|
end
|
506
564
|
end
|
507
565
|
|
508
566
|
%w[flat_map collect_concat].each do |method|
|
509
567
|
describe_enum_method method do
|
510
|
-
let(:enum){ 20.times.map{ |i|
|
568
|
+
let(:enum){ 20.times.map{ |i| RandItem.new(i) }.each_slice(3) }
|
511
569
|
let(:runner){ proc{ |a| a.map(&:value) } }
|
512
570
|
|
513
|
-
it
|
514
|
-
expect(enum.in_threads.send(method, &runner)).
|
571
|
+
it 'should return same result with threads' do
|
572
|
+
expect(enum.in_threads.send(method, &runner)).
|
573
|
+
to eq(enum.send(method, &runner))
|
515
574
|
end
|
516
575
|
|
517
|
-
it
|
518
|
-
enum.send(method)
|
519
|
-
|
576
|
+
it 'should fire same objects' do
|
577
|
+
enum.send(method) do |a|
|
578
|
+
a.each do |o|
|
579
|
+
expect(o).to receive(:touch).with(a).once
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
enum.in_threads.send(method) do |a|
|
584
|
+
a.each do |o|
|
585
|
+
o.touch_n_value(a)
|
586
|
+
end
|
587
|
+
end
|
520
588
|
end
|
521
589
|
|
522
|
-
it
|
523
|
-
expect(measure{ enum.in_threads.send(method, &runner) }).
|
590
|
+
it 'should run faster with threads' do
|
591
|
+
expect(measure{ enum.in_threads.send(method, &runner) }).
|
592
|
+
to be < measure{ enum.send(method, &runner) } * speed_coef
|
524
593
|
end
|
525
594
|
|
526
|
-
it
|
527
|
-
expect(enum.in_threads.send(method).to_a).
|
595
|
+
it 'should return same enum without block' do
|
596
|
+
expect(enum.in_threads.send(method).to_a).
|
597
|
+
to eq(enum.send(method).to_a)
|
528
598
|
end
|
529
599
|
|
530
|
-
it
|
600
|
+
it 'should raise exception in outer thread' do
|
531
601
|
check_test_exception(enum) do |threaded|
|
532
|
-
threaded.send(method){
|
602
|
+
threaded.send(method){ fail TestException }
|
533
603
|
end
|
534
604
|
end
|
535
605
|
end
|
536
606
|
end
|
537
607
|
|
538
|
-
context
|
608
|
+
context 'unthreaded' do
|
539
609
|
%w[inject reduce].each do |method|
|
540
610
|
describe method do
|
541
|
-
it
|
611
|
+
it 'should return same result' do
|
542
612
|
combiner = proc{ |memo, o| memo + o.value }
|
543
|
-
expect(enum.in_threads.send(method, 0, &combiner)).
|
613
|
+
expect(enum.in_threads.send(method, 0, &combiner)).
|
614
|
+
to eq(enum.send(method, 0, &combiner))
|
544
615
|
end
|
545
616
|
|
546
|
-
it
|
617
|
+
it 'should raise exception in outer thread' do
|
547
618
|
check_test_exception(enum) do |threaded|
|
548
|
-
threaded.send(method){
|
619
|
+
threaded.send(method){ fail TestException }
|
549
620
|
end
|
550
621
|
end
|
551
622
|
end
|
@@ -553,14 +624,15 @@ describe "in_threads" do
|
|
553
624
|
|
554
625
|
%w[max min minmax sort].each do |method|
|
555
626
|
describe method do
|
556
|
-
it
|
627
|
+
it 'should return same result' do
|
557
628
|
comparer = proc{ |a, b| a.value <=> b.value }
|
558
|
-
expect(enum.in_threads.send(method, &comparer)).
|
629
|
+
expect(enum.in_threads.send(method, &comparer)).
|
630
|
+
to eq(enum.send(method, &comparer))
|
559
631
|
end
|
560
632
|
|
561
|
-
it
|
633
|
+
it 'should raise exception in outer thread' do
|
562
634
|
check_test_exception(enum) do |threaded|
|
563
|
-
threaded.send(method){
|
635
|
+
threaded.send(method){ fail TestException }
|
564
636
|
end
|
565
637
|
end
|
566
638
|
end
|
@@ -568,7 +640,7 @@ describe "in_threads" do
|
|
568
640
|
|
569
641
|
%w[to_a entries].each do |method|
|
570
642
|
describe method do
|
571
|
-
it
|
643
|
+
it 'should return same result' do
|
572
644
|
expect(enum.in_threads.send(method)).to eq(enum.send(method))
|
573
645
|
end
|
574
646
|
end
|
@@ -576,7 +648,7 @@ describe "in_threads" do
|
|
576
648
|
|
577
649
|
%w[drop take].each do |method|
|
578
650
|
describe method do
|
579
|
-
it
|
651
|
+
it 'should return same result' do
|
580
652
|
expect(enum.in_threads.send(method, 2)).to eq(enum.send(method, 2))
|
581
653
|
end
|
582
654
|
end
|
@@ -584,7 +656,7 @@ describe "in_threads" do
|
|
584
656
|
|
585
657
|
%w[first].each do |method|
|
586
658
|
describe method do
|
587
|
-
it
|
659
|
+
it 'should return same result' do
|
588
660
|
expect(enum.in_threads.send(method)).to eq(enum.send(method))
|
589
661
|
expect(enum.in_threads.send(method, 3)).to eq(enum.send(method, 3))
|
590
662
|
end
|
@@ -593,35 +665,38 @@ describe "in_threads" do
|
|
593
665
|
|
594
666
|
%w[include? member?].each do |method|
|
595
667
|
describe method do
|
596
|
-
it
|
597
|
-
expect(enum.in_threads.send(method, enum[10])).
|
668
|
+
it 'should return same result' do
|
669
|
+
expect(enum.in_threads.send(method, enum[10])).
|
670
|
+
to eq(enum.send(method, enum[10]))
|
598
671
|
end
|
599
672
|
end
|
600
673
|
end
|
601
674
|
|
602
|
-
describe_enum_method
|
675
|
+
describe_enum_method 'each_with_object' do
|
603
676
|
let(:runner){ proc{ |o, h| h[o.value] = true } }
|
604
677
|
|
605
|
-
it
|
606
|
-
expect(enum.in_threads.each_with_object({}, &runner)).
|
678
|
+
it 'should return same result' do
|
679
|
+
expect(enum.in_threads.each_with_object({}, &runner)).
|
680
|
+
to eq(enum.each_with_object({}, &runner))
|
607
681
|
end
|
608
682
|
|
609
|
-
it
|
683
|
+
it 'should raise exception in outer thread' do
|
610
684
|
check_test_exception(enum) do |threaded|
|
611
|
-
threaded.each_with_object({}){
|
685
|
+
threaded.each_with_object({}){ fail TestException }
|
612
686
|
end
|
613
687
|
end
|
614
688
|
end
|
615
689
|
|
616
690
|
%w[chunk slice_before].each do |method|
|
617
691
|
describe_enum_method method do
|
618
|
-
it
|
619
|
-
expect(enum.in_threads.send(method, &:check?).to_a).
|
692
|
+
it 'should return same result' do
|
693
|
+
expect(enum.in_threads.send(method, &:check?).to_a).
|
694
|
+
to eq(enum.send(method, &:check?).to_a)
|
620
695
|
end
|
621
696
|
|
622
|
-
it
|
697
|
+
it 'should raise exception in outer thread' do
|
623
698
|
check_test_exception(enum) do |threaded|
|
624
|
-
threaded.send(method){
|
699
|
+
threaded.send(method){ fail TestException }.to_a
|
625
700
|
end
|
626
701
|
end
|
627
702
|
end
|