proco 0.0.1

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.
@@ -0,0 +1,197 @@
1
+ $VERBOSE = true
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) if $0 == __FILE__
3
+ require 'rubygems'
4
+ require 'minitest/autorun'
5
+ require 'proco'
6
+ require 'parallelize'
7
+ require 'logger'
8
+
9
+ describe Proco do
10
+ before do
11
+ @logger = Logger.new($stdout)
12
+ end
13
+
14
+ it "can be created with method chaining" do
15
+ proco = Proco.interval(1).threads(4).queues(4).queue_size(100).batch(true).logger(@logger).new
16
+ opts = proco.options
17
+
18
+ assert_equal 1, opts[:interval]
19
+ assert_equal 4, opts[:threads]
20
+ assert_equal 4, opts[:queues]
21
+ assert_equal 100, opts[:queue_size]
22
+ assert_equal true, opts[:batch]
23
+ assert_equal @logger, opts[:logger]
24
+
25
+ proco = Proco.threads(8).interval(10).new(:interval => 20)
26
+ opts = proco.options
27
+ assert_equal 20, opts[:interval]
28
+ assert_equal 8, opts[:threads]
29
+ end
30
+
31
+ describe "in default setting" do
32
+ before do
33
+ @proco = Proco.new
34
+ end
35
+
36
+ it "yields each item" do
37
+ @proco.start do |items|
38
+ assert_equal false, items.is_a?(Array)
39
+ end
40
+
41
+ @proco.submit! 1
42
+ @proco.submit 2
43
+
44
+ @proco.exit
45
+ end
46
+
47
+ it "acts as a FCFS queue" do
48
+ processed = []
49
+ @proco.start do |item|
50
+ processed << item
51
+ end
52
+
53
+ feed = []
54
+ 100.times do |i|
55
+ feed << i
56
+ @proco.submit! i
57
+ end
58
+ @proco.exit
59
+
60
+ assert_equal feed, processed
61
+ assert_equal 100, processed.length
62
+ end
63
+ end
64
+
65
+ describe "in batch-mode with multiple queues" do
66
+ before do
67
+ @proco = Proco.queue_size(10).queues(2).threads(4).batch(true).logger(@logger).new
68
+ @mutex = Mutex.new
69
+ end
70
+
71
+ it "always yields Array" do
72
+ bool = true
73
+ @proco.start do |items|
74
+ assert items.is_a?(Array)
75
+ end
76
+ @proco.submit 1
77
+ @proco.submit 2
78
+ @proco.submit! 3
79
+
80
+ @proco.exit
81
+ end
82
+
83
+ it "handles synchronous requests" do
84
+ cnt = 0
85
+ @proco.start do |items|
86
+ @mutex.synchronize do
87
+ cnt += items.inject(:+)
88
+ end
89
+ end
90
+ 1000.times { |i| @proco.submit i }
91
+ assert_equal 1000.times.inject(:+), cnt
92
+
93
+ @proco.exit
94
+ end
95
+
96
+ it "handles asynchronous requests" do
97
+ cnt = 0
98
+ @proco.start do |items|
99
+ @mutex.synchronize do
100
+ cnt += items.inject(:+)
101
+ end
102
+ end
103
+ 1000.times { |i| @proco.submit! i }
104
+ @proco.exit
105
+ assert_equal 1000.times.inject(:+), cnt
106
+ end
107
+ end
108
+
109
+ describe "in batch mode" do
110
+ it "yields batch_size items if set" do
111
+ proco = Proco.interval(0.1).batch_size(10).queue_size(1000).batch(true).new
112
+ cnt = 0
113
+ proco.start do |items|
114
+ # FIXME: naive
115
+ assert_equal 10, items.length
116
+ cnt += 1
117
+ end
118
+
119
+ 100.times do |i|
120
+ proco.submit! i
121
+ end
122
+ proco.exit
123
+ assert_equal 10, cnt
124
+ end
125
+
126
+ it "works as follows" do
127
+ proco = Proco.interval(0.1).threads(4).queues(8).queue_size(10).batch(true).new
128
+
129
+ assert_equal false, proco.running?
130
+
131
+ # No you can't submit an item yet
132
+ assert_raises(RuntimeError) { proco.submit :not_yet }
133
+ assert_raises(RuntimeError) { proco.exit }
134
+ assert_raises(RuntimeError) { proco.kill }
135
+
136
+ assert_raises(ArgumentError) {
137
+ proco.start
138
+ }
139
+
140
+ proco.start do |batch|
141
+ # Batch-process items every 0.1 seconds
142
+ # ...
143
+ # puts "#{Thread.current}: #{batch}"
144
+ batch.length
145
+ end
146
+
147
+ assert_equal true, proco.running?
148
+
149
+ # Synchronous submit
150
+ 50.times do |i|
151
+ result = proco.submit i
152
+ assert_instance_of Fixnum, result
153
+ end
154
+
155
+ # Asynchronous submit
156
+ futures = 50.times.map { |i|
157
+ proco.submit! i
158
+ }
159
+ futures.each do |future|
160
+ assert_instance_of Proco::Future, future
161
+ end
162
+
163
+ # Wait until the batch containing the item is processed
164
+ assert_equal 50, futures.uniq.map { |f| f.get }.inject(:+)
165
+
166
+ proco.exit
167
+ assert_equal false, proco.running?
168
+ end
169
+
170
+ end
171
+
172
+ it "can be killed without waiting" do
173
+ proco = Proco.batch(true).new
174
+ cnt = 0
175
+ proco.start do |items|
176
+ sleep 1
177
+ cnt += items.length
178
+ end
179
+ 100.times do |i|
180
+ proco.submit! i
181
+ end
182
+ proco.exit
183
+ assert_equal 100, cnt
184
+
185
+ cnt = 0
186
+ proco.start do |items|
187
+ sleep 1
188
+ cnt += items.length
189
+ end
190
+ 100.times do |i|
191
+ proco.submit! i
192
+ end
193
+ proco.kill
194
+ assert_equal 0, cnt
195
+ end
196
+ end
197
+
@@ -0,0 +1,105 @@
1
+ $VERBOSE = true
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) if $0 == __FILE__
3
+ require 'rubygems'
4
+ require 'minitest/autorun'
5
+ require 'proco'
6
+ require 'lps'
7
+
8
+ class TestQueue < MiniTest::Unit::TestCase
9
+ def test_single_queue
10
+ q = Proco::Queue::SingleQueue.new 100
11
+ f = q.push 1
12
+ assert_instance_of Proco::Future, f
13
+ q.push 2
14
+
15
+ f2, i = q.take
16
+ assert_equal f, f2
17
+ assert_equal 1, i
18
+
19
+ f3, i = q.take
20
+ assert_equal 2, i
21
+ end
22
+
23
+ def test_batch_queue
24
+ q = Proco::Queue::BatchQueue.new 100, 10
25
+
26
+ futures = 10.times.map { |i| q.push i }
27
+ assert_equal 1, futures.uniq.length
28
+
29
+ future = futures.first
30
+ future2 = q.push :next
31
+ assert future != future2
32
+
33
+ f, items = q.take
34
+ assert_equal future, f
35
+ assert_equal 10.times.to_a, items
36
+
37
+ f, items = q.take
38
+ assert_equal future2, f
39
+ assert_equal [:next], items
40
+
41
+ f = q.push :next
42
+ assert future2 != f
43
+ end
44
+
45
+ def test_multi_queue
46
+ q = Proco::Queue::MultiQueue.new 100
47
+ f1 = q.push 1
48
+ f2 = q.push 2
49
+ f3 = q.push 3
50
+ assert_equal f1, f2
51
+ assert_equal f2, f3
52
+
53
+ f4, items = q.take
54
+ assert_equal f3, f4
55
+ assert_equal [1, 2, 3], items
56
+
57
+ f5 = q.push 4
58
+ assert ! f4 != f5
59
+
60
+ f6, items = q.take
61
+ assert_equal f5, f6
62
+ assert_equal [4], items
63
+ end
64
+
65
+ def test_multi_queue_complex
66
+ queue = Proco::Queue::MultiQueue.new(200)
67
+ futures = []
68
+ num_batches = 0
69
+ num_items = 0
70
+
71
+ t1 = Thread.new {
72
+ 1000.times do |i|
73
+ futures << queue.push(i)
74
+ end
75
+ queue.invalidate
76
+ }
77
+
78
+ t2 = Thread.new {
79
+ future = items = nil
80
+ begin
81
+ LPS.freq(10).while {
82
+ future, items = queue.take
83
+ future
84
+ }.loop do
85
+ num_batches += 1
86
+ num_items += items.length
87
+
88
+ future.update do
89
+ items.length
90
+ end
91
+ end
92
+ rescue Exception => e
93
+ puts e
94
+ end
95
+ }
96
+
97
+ t1.join
98
+ t2.join
99
+
100
+ assert_equal 1000, futures.length
101
+ assert_equal num_batches, futures.uniq.length
102
+ assert_equal 1000, num_items
103
+ assert_equal 1000, futures.uniq.map { |future| future.get }.inject(:+)
104
+ end
105
+ end
@@ -0,0 +1,19 @@
1
+ $VERBOSE = true
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) if $0 == __FILE__
3
+ require 'rubygems'
4
+ require 'minitest/autorun'
5
+ require 'proco'
6
+
7
+ class TestWorker < MiniTest::Unit::TestCase
8
+ def test_worker
9
+ w = Proco::MT::Worker.new nil
10
+ cnt = 0
11
+ w.assign { sleep 0.1; cnt += 1 }
12
+ w.assign { sleep 0.1; cnt += 1 }
13
+ w.assign { sleep 0.1; cnt += 1 } # Async
14
+ assert_equal 1, cnt
15
+ sleep 0.2;
16
+ w.exit
17
+ assert_equal 3, cnt
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: proco
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Junegunn Choi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: lps
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.1.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: option_initializer
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.2.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.2.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: minitest
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: parallelize
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: A lightweight asynchronous task executor service designed for efficient
79
+ batch processing
80
+ email:
81
+ - junegunn.c@gmail.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - LICENSE.txt
89
+ - README.md
90
+ - Rakefile
91
+ - benchmark/comparison.rb
92
+ - benchmark/submission.rb
93
+ - lib/proco.rb
94
+ - lib/proco/dispatcher.rb
95
+ - lib/proco/future.rb
96
+ - lib/proco/logger.rb
97
+ - lib/proco/mt/base.rb
98
+ - lib/proco/mt/pool.rb
99
+ - lib/proco/mt/threaded.rb
100
+ - lib/proco/mt/worker.rb
101
+ - lib/proco/queue/base.rb
102
+ - lib/proco/queue/batch_queue.rb
103
+ - lib/proco/queue/multi_queue.rb
104
+ - lib/proco/queue/single_queue.rb
105
+ - lib/proco/version.rb
106
+ - proco.gemspec
107
+ - test/test_mt_base.rb
108
+ - test/test_mt_threaded.rb
109
+ - test/test_pool.rb
110
+ - test/test_proco.rb
111
+ - test/test_queue.rb
112
+ - test/test_worker.rb
113
+ homepage: https://github.com/junegunn/proco
114
+ licenses: []
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ none: false
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubyforge_project:
133
+ rubygems_version: 1.8.25
134
+ signing_key:
135
+ specification_version: 3
136
+ summary: A lightweight asynchronous task executor service designed for efficient batch
137
+ processing
138
+ test_files:
139
+ - test/test_mt_base.rb
140
+ - test/test_mt_threaded.rb
141
+ - test/test_pool.rb
142
+ - test/test_proco.rb
143
+ - test/test_queue.rb
144
+ - test/test_worker.rb