multiprocessing 0.0.1 → 0.0.2

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.
@@ -3,138 +3,382 @@ require 'timeout'
3
3
 
4
4
  describe MultiProcessing::Queue do
5
5
 
6
- it "can be created" do
7
- MultiProcessing::Queue.new.should be_instance_of MultiProcessing::Queue
6
+ before do
7
+ @queue = MultiProcessing::Queue.new
8
8
  end
9
9
 
10
- it "#length returns its length" do
11
- queue = MultiProcessing::Queue.new
12
- queue.length.should == 0
13
- queue.push :a
14
- sleep 0.1 # wait for enqueue
15
- queue.length.should == 1
16
- queue.push :b
17
- sleep 0.1 # wait for enqueue
18
- queue.length.should == 2
19
- queue.pop
20
- queue.length.should == 1
21
- queue.pop
22
- queue.length.should == 0
10
+ describe "#enq" do
11
+
12
+ context "passed a normal object" do
13
+ it "returns itself" do
14
+ retval = @queue.enq :nyan
15
+ retval.should === @queue
16
+ end
17
+ end
18
+
19
+ context "passed an un-serializable object" do
20
+ it "raises TypeError/ArgumentError" do
21
+ proc{ @queue.enq proc{} }.should raise_error TypeError
22
+ end
23
+ end
24
+
25
+ context "already closed" do
26
+ it "raises QueueError" do
27
+ @queue.close
28
+ proc{ @queue.enq :nyan } .should raise_error MultiProcessing::QueueError
29
+ end
30
+ end
31
+
23
32
  end
24
33
 
25
- it "can pass object across processes" do
26
- queue = MultiProcessing::Queue.new
27
- data_list = [:nyan, [:cat, :dog]]
28
- fork do
29
- data_list.each do |data|
30
- queue.push data
31
- end
32
- sleep 0.1
33
- end
34
- result = []
35
- timeout(1) do
36
- data_list.length.times do
37
- result << queue.pop
38
- end
39
- end
40
- result.should == data_list
41
- end
42
-
43
- it "can pass large objects across processes" do
44
- queue1 = MultiProcessing::Queue.new
45
- queue2 = MultiProcessing::Queue.new
46
- data = "a" * 1024 * 1024 * 16 # 16MB
47
- timeout_sec = 10
48
- # process to echo queue1 -> queue 2
49
- process = MultiProcessing::Process.new do
50
- echo_queue = ::Queue.new
51
- Thread.new do
52
- loop do
53
- echo_queue.push queue1.pop
34
+ describe "#deq" do
35
+
36
+ before do
37
+ @data_set = [ 123, 3.14, "neko", [1,2,3], {:cat=>"nyan", :dog=>"wan"} ]
38
+ end
39
+
40
+ context "enqueued from same process" do
41
+ it "returns correct object" do
42
+ @data_set.each do |data|
43
+ @queue.enq data
44
+ @queue.deq.should == data
45
+ end
46
+ end
47
+ end
48
+
49
+ context "enqueued from another process" do
50
+ it "returns correct object" do
51
+ pid = fork do
52
+ @data_set.each do |data|
53
+ @queue.enq data
54
+ end
55
+ sleep 1
56
+ end
57
+
58
+ ret = []
59
+ @data_set.length.times do
60
+ ret << @queue.deq
61
+ end
62
+ ret.should == @data_set
63
+
64
+ begin
65
+ Process.kill :TERM, pid
66
+ rescue Errno::ESRCH
54
67
  end
55
68
  end
56
- Thread.new do
57
- loop do
58
- queue2.push echo_queue.pop
69
+ end
70
+
71
+ context "nob-block mode" do
72
+
73
+ context "the queue holds no item" do
74
+ it "raises QueueError" do
75
+ proc{ @queue.deq(true) }.should raise_error MultiProcessing::QueueError
76
+ end
77
+ end
78
+
79
+ context "the queue holds items" do
80
+ it "returns correct object" do
81
+ pid = fork do
82
+ @queue.enq :data
83
+ sleep 1
84
+ end
85
+ sleep 0.05
86
+
87
+ ret = @queue.deq(true)
88
+ ret.should == :data
89
+
90
+ begin
91
+ Process.kill :TERM, pid
92
+ rescue Errno::ESRCH
93
+ end
59
94
  end
60
95
  end
61
- sleep timeout_sec + 1
96
+
62
97
  end
63
- result = nil
64
- timeout(timeout_sec) do
65
- queue1.push data
66
- result = queue2.pop
98
+
99
+
100
+ end
101
+
102
+ describe "#close" do
103
+ it "returns itself" do
104
+ @queue.close.should === @queue
67
105
  end
68
- process.kill :TERM
69
- result.should == data
70
106
  end
71
107
 
72
- it "can pass as many as objects across processes" do
73
- queue1 = MultiProcessing::Queue.new
74
- queue2 = MultiProcessing::Queue.new
75
- data_list = Array.new(1000){|i| "a"*1000 }
76
- timeout_sec = 10
77
- # process to echo queue1 -> queue 2
78
- process = MultiProcessing::Process.new do
79
- echo_queue = ::Queue.new
80
- Thread.new do
81
- loop do
82
- echo_queue.push queue1.pop
108
+ describe "#join_thread" do
109
+
110
+ context "before close" do
111
+ it "raises QueueError" do
112
+ proc{@queue.join_thread}.should raise_error MultiProcessing::QueueError
113
+ end
114
+ end
115
+
116
+ context "after close" do
117
+
118
+ context "data have never enqueued" do
119
+ it "returns immediatelyl" do
120
+ @queue.close
121
+ proc{timeout(0.1){ @queue.join_thread }}.should_not raise_error Timeout::Error
83
122
  end
84
123
  end
85
- Thread.new do
86
- loop do
87
- queue2.push echo_queue.pop
124
+
125
+ context "data had been enqueued" do
126
+
127
+ it "joins enque thread" do
128
+ data = "a" * 1024*65 # > pipe capacity(64K)
129
+ @queue.enq data
130
+ @queue.close
131
+ proc{timeout(0.1){ @queue.join_thread }}.should raise_error Timeout::Error
132
+ @queue.deq
133
+ proc{timeout(0.1){ @queue.join_thread }}.should_not raise_error Timeout::Error
134
+ end
135
+
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "#length" do
141
+ it "returns a number of items" do
142
+ @queue.length.should == 0
143
+ @queue.enq :a
144
+ @queue.length.should == 1
145
+ @queue.enq :a
146
+ @queue.length.should == 2
147
+ @queue.deq
148
+ @queue.length.should == 1
149
+ @queue.deq
150
+ @queue.length.should == 0
151
+ end
152
+ end
153
+
154
+ describe "#empty?" do
155
+
156
+ context "the queue holds no item" do
157
+ it "returns true" do
158
+ @queue.should be_empty
159
+ end
160
+ end
161
+
162
+ context "the queue has item(s)" do
163
+ it "returns false" do
164
+ @queue.enq :a
165
+ @queue.should_not be_empty
166
+ end
167
+ end
168
+
169
+ end
170
+
171
+ describe "#clear" do
172
+
173
+ context "the queue holds no item" do
174
+ it "do nothing and returns itself" do
175
+ ret = @queue.clear
176
+ @queue.length.should == 0
177
+ ret.should === @queue
178
+ end
179
+ end
180
+
181
+ context "the queue holds items" do
182
+ it "clears its items and returns itself" do
183
+ @queue.enq :a
184
+ @queue.enq :a
185
+ ret = @queue.clear
186
+ @queue.length.should == 0
187
+ ret.should === @queue
188
+ end
189
+ end
190
+
191
+ end
192
+
193
+ context "heavy load given" do
194
+
195
+ before do
196
+
197
+ @queue1 = @queue
198
+ @queue2 = MultiProcessing::Queue.new
199
+ # process to echo queue1 -> queue 2
200
+ @pid = fork do
201
+ echo_queue = ::Queue.new
202
+ Thread.new do
203
+ loop do
204
+ echo_queue.push @queue1.pop
205
+ end
206
+ end
207
+ Thread.new do
208
+ loop do
209
+ @queue2.push echo_queue.pop
210
+ end
88
211
  end
212
+ sleep
89
213
  end
90
- sleep timeout_sec + 1
214
+
91
215
  end
92
- result = []
93
- timeout(timeout_sec) do
94
- Thread.new do
95
- data_list.each do |data|
96
- queue1.push data
216
+
217
+ context "many data given" do
218
+ it "throughs correct data" do
219
+ data = Array.new(1000){"a"*100} # 100byte * 1000
220
+ data.each do |item|
221
+ @queue1.enq item
222
+ end
223
+ res = []
224
+ data.length.times do
225
+ res << @queue2.deq
97
226
  end
227
+ res.should == data
98
228
  end
99
- data_list.length.times do
100
- result << queue2.pop
229
+ end
230
+
231
+ context "long data given" do
232
+ it "throughs correct data" do
233
+ data = "a" * 1024 * 1024 # 1 MB
234
+ @queue1.enq data
235
+ res = @queue2.deq
236
+ res.should == data
101
237
  end
102
238
  end
103
- process.kill :TERM
104
- result.should == data_list
239
+
240
+ after do
241
+ begin
242
+ Process.kill :TERM, @pid
243
+ rescue Errno::ESRCH
244
+ end
245
+ end
246
+
105
247
  end
106
248
 
107
- it "can be closed and joined enqueue thread before enqueue" do
249
+ end
250
+ __END__
251
+ describe "#length" do
252
+
253
+ it "returns its length" do
108
254
  queue = MultiProcessing::Queue.new
109
- thread = Thread.new { queue.close.join_thread }
110
- thread.join.should_not be_nil
255
+ queue.length.should == 0
256
+ queue.push :a
257
+ sleep 0.1 # wait for enqueue
258
+ queue.length.should == 1
259
+ queue.push :b
260
+ sleep 0.1 # wait for enqueue
261
+ queue.length.should == 2
262
+ queue.pop
263
+ queue.length.should == 1
264
+ queue.pop
265
+ queue.length.should == 0
111
266
  end
267
+ end
112
268
 
113
- it "can be closed and joined enqueue thread after enqueue" do
114
- queue = MultiProcessing::Queue.new
115
- data_list = Array.new(1000){|i| "a"*1000 }
116
- timeout_sec = 10
117
- process = MultiProcessing::Process.new do
118
- data_list.length.times do
119
- queue.pop
269
+ it "can pass object across processes" do
270
+ queue = MultiProcessing::Queue.new
271
+ data_list = [:nyan, [:cat, :dog]]
272
+ fork do
273
+ data_list.each do |data|
274
+ queue.push data
275
+ end
276
+ sleep 0.1
277
+ end
278
+ result = []
279
+ timeout(1) do
280
+ data_list.length.times do
281
+ result << queue.pop
282
+ end
283
+ end
284
+ result.should == data_list
285
+ end
286
+
287
+ it "can pass large objects across processes" do
288
+ queue1 = MultiProcessing::Queue.new
289
+ queue2 = MultiProcessing::Queue.new
290
+ data = "a" * 1024 * 1024 * 16 # 16MB
291
+ timeout_sec = 10
292
+ # process to echo queue1 -> queue 2
293
+ pid = fork do
294
+ echo_queue = ::Queue.new
295
+ Thread.new do
296
+ loop do
297
+ echo_queue.push queue1.pop
298
+ end
299
+ end
300
+ Thread.new do
301
+ loop do
302
+ queue2.push echo_queue.pop
303
+ end
304
+ end
305
+ sleep timeout_sec + 1
306
+ end
307
+ result = nil
308
+ timeout(timeout_sec) do
309
+ queue1.push data
310
+ result = queue2.pop
311
+ end
312
+ Process.kill :TERM,pid
313
+ result.should == data
314
+ end
315
+
316
+ it "can pass as many as objects across processes" do
317
+ queue1 = MultiProcessing::Queue.new
318
+ queue2 = MultiProcessing::Queue.new
319
+ data_list = Array.new(1000){|i| "a"*1000 }
320
+ timeout_sec = 10
321
+ # process to echo queue1 -> queue 2
322
+ pid = fork do
323
+ echo_queue = ::Queue.new
324
+ Thread.new do
325
+ loop do
326
+ echo_queue.push queue1.pop
327
+ end
328
+ end
329
+ Thread.new do
330
+ loop do
331
+ queue2.push echo_queue.pop
120
332
  end
121
- sleep timeout_sec + 1
122
333
  end
123
- th = Thread.new do
334
+ sleep timeout_sec + 1
335
+ end
336
+ result = []
337
+ timeout(timeout_sec) do
338
+ Thread.new do
124
339
  data_list.each do |data|
125
- queue.push data
340
+ queue1.push data
126
341
  end
127
- queue.close.join_thread
128
342
  end
129
- th.join(timeout_sec).should_not be_nil
130
- process.kill(:TERM)
343
+ data_list.length.times do
344
+ result << queue2.pop
345
+ end
131
346
  end
347
+ Process.kill :TERM,pid
348
+ result.should == data_list
349
+ end
132
350
 
133
- it "cannot be joined before being closed" do
134
- queue = MultiProcessing::Queue.new
135
- proc{ queue.join_thread }.should raise_error MultiProcessing::QueueError
351
+ it "can be closed and joined enqueue thread before enqueue" do
352
+ queue = MultiProcessing::Queue.new
353
+ thread = Thread.new { queue.close.join_thread }
354
+ thread.join.should_not be_nil
355
+ end
356
+
357
+ it "can be closed and joined enqueue thread after enqueue" do
358
+ queue = MultiProcessing::Queue.new
359
+ data_list = Array.new(1000){|i| "a"*1000 }
360
+ timeout_sec = 10
361
+ pid = fork do
362
+ data_list.length.times do
363
+ queue.pop
364
+ end
365
+ sleep timeout_sec + 1
366
+ end
367
+ th = Thread.new do
368
+ data_list.each do |data|
369
+ queue.push data
370
+ end
371
+ queue.close.join_thread
136
372
  end
373
+ th.join(timeout_sec).should_not be_nil
374
+ Process.kill :TERM,pid
375
+ end
137
376
 
377
+ it "cannot be joined before being closed" do
378
+ queue = MultiProcessing::Queue.new
379
+ proc{ queue.join_thread }.should raise_error MultiProcessing::QueueError
138
380
  end
139
381
 
382
+ end
383
+
140
384