in_threads 1.2.2 → 1.3.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 +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
|