parallizer 0.2.3 → 0.2.4
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.
- data/Gemfile.lock +3 -1
- data/lib/parallizer/thread_pool.rb +63 -0
- data/lib/parallizer/version.rb +1 -1
- data/lib/parallizer.rb +4 -20
- data/parallizer.gemspec +1 -1
- data/spec/parallizer_spec.rb +41 -23
- metadata +10 -9
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
parallizer (0.2.
|
4
|
+
parallizer (0.2.3)
|
5
5
|
work_queue (~> 2.5.2)
|
6
6
|
|
7
7
|
GEM
|
@@ -9,6 +9,7 @@ GEM
|
|
9
9
|
specs:
|
10
10
|
always_execute (0.1.3)
|
11
11
|
diff-lcs (1.1.3)
|
12
|
+
rake (0.9.2.2)
|
12
13
|
rspec (2.9.0)
|
13
14
|
rspec-core (~> 2.9.0)
|
14
15
|
rspec-expectations (~> 2.9.0)
|
@@ -25,4 +26,5 @@ PLATFORMS
|
|
25
26
|
DEPENDENCIES
|
26
27
|
always_execute (~> 0.1.1)
|
27
28
|
parallizer!
|
29
|
+
rake
|
28
30
|
rspec (~> 2.9.0)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
class Parallizer
|
4
|
+
# Initially taken from Celluloid. -mgp
|
5
|
+
module ThreadPool
|
6
|
+
THEAD_POOL_SIZE = 16
|
7
|
+
|
8
|
+
@pool = []
|
9
|
+
@mutex = Mutex.new
|
10
|
+
|
11
|
+
@max_idle = THEAD_POOL_SIZE
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :max_idle
|
15
|
+
|
16
|
+
# Get a thread from the pool, running the given block
|
17
|
+
def get(&block)
|
18
|
+
@mutex.synchronize do
|
19
|
+
begin
|
20
|
+
if @pool.empty?
|
21
|
+
thread = create
|
22
|
+
else
|
23
|
+
thread = @pool.shift
|
24
|
+
end
|
25
|
+
end until thread.status # handle crashed threads
|
26
|
+
|
27
|
+
thread[:queue] << block
|
28
|
+
thread
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return a thread to the pool
|
33
|
+
def put(thread)
|
34
|
+
@mutex.synchronize do
|
35
|
+
if @pool.size >= @max_idle
|
36
|
+
thread[:queue] << nil
|
37
|
+
else
|
38
|
+
@pool << thread
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Create a new thread with an associated queue of procs to run
|
44
|
+
def create
|
45
|
+
queue = Queue.new
|
46
|
+
thread = Thread.new do
|
47
|
+
while proc = queue.pop
|
48
|
+
begin
|
49
|
+
proc.call
|
50
|
+
rescue => ex
|
51
|
+
# Let this thread die on exceptions other than standard errors
|
52
|
+
end
|
53
|
+
put thread
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
thread[:queue] = queue
|
58
|
+
thread
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
data/lib/parallizer/version.rb
CHANGED
data/lib/parallizer.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require 'work_queue'
|
2
1
|
require 'parallizer/version'
|
3
2
|
require 'parallizer/proxy'
|
4
3
|
require 'parallizer/method_call_notifier'
|
4
|
+
require 'parallizer/thread_pool'
|
5
5
|
|
6
6
|
class Parallizer
|
7
|
-
WORK_QUEUE_SIZE =
|
7
|
+
WORK_QUEUE_SIZE = Parallizer::ThreadPool::THEAD_POOL_SIZE
|
8
8
|
|
9
9
|
attr_reader :calls, :call_infos, :client, :proxy, :options
|
10
10
|
|
@@ -49,27 +49,10 @@ class Parallizer
|
|
49
49
|
Parallizer::Proxy.new(client, call_infos)
|
50
50
|
end
|
51
51
|
|
52
|
-
def self.work_queue
|
53
|
-
@parallizer_work_queue ||= create_work_queue
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.create_work_queue
|
57
|
-
work_queue = WorkQueue.new(WORK_QUEUE_SIZE)
|
58
|
-
|
59
|
-
# Force threads to be available - the work_queue gem seems to not always create the threads
|
60
|
-
WORK_QUEUE_SIZE.times do |i|
|
61
|
-
work_queue.enqueue_b do
|
62
|
-
1000.times { |i| i ** 1000 }
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
work_queue
|
67
|
-
end
|
68
|
-
|
69
52
|
private
|
70
53
|
|
71
54
|
def enqueue_call_info(call_info, method_name_and_args)
|
72
|
-
Parallizer.
|
55
|
+
Parallizer::ThreadPool.get do
|
73
56
|
call_info[:mutex].synchronize do
|
74
57
|
begin
|
75
58
|
(call_info[:retries] + 1).times do
|
@@ -84,6 +67,7 @@ class Parallizer
|
|
84
67
|
ensure
|
85
68
|
call_info[:complete?] = true
|
86
69
|
call_info[:condition_variable].broadcast
|
70
|
+
Parallizer::ThreadPool.put(Thread.current)
|
87
71
|
end
|
88
72
|
end
|
89
73
|
end
|
data/parallizer.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.
|
21
|
+
s.add_development_dependency 'rake'
|
22
22
|
s.add_development_dependency 'rspec', '~> 2.9.0'
|
23
23
|
s.add_development_dependency 'always_execute', '~> 0.1.1'
|
24
24
|
end
|
data/spec/parallizer_spec.rb
CHANGED
@@ -21,12 +21,6 @@ describe Parallizer do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
describe "#work_queue" do
|
25
|
-
it "should have WORK_QUEUE_SIZE threads" do
|
26
|
-
Parallizer.work_queue.cur_threads.should == Parallizer::WORK_QUEUE_SIZE
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
24
|
describe "#add" do
|
31
25
|
before do
|
32
26
|
@client = TestObject.new
|
@@ -168,25 +162,49 @@ describe Parallizer do
|
|
168
162
|
end
|
169
163
|
end
|
170
164
|
|
171
|
-
context "with
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
parallizer
|
182
|
-
parallizer.add.another_method
|
165
|
+
context "with exceptions that are not standard errors" do
|
166
|
+
before do
|
167
|
+
@retries = 3
|
168
|
+
@client = stub('a client')
|
169
|
+
@method = :a_failing_method
|
170
|
+
(@retries + 1).times { @client.should_receive(@method).and_raise(Exception.new('an error')) }
|
171
|
+
end
|
172
|
+
|
173
|
+
execute do
|
174
|
+
parallizer = Parallizer.new(@client, :retries => @retries)
|
175
|
+
parallizer.add_call(@method)
|
183
176
|
proxy = parallizer.create_proxy
|
184
|
-
|
185
|
-
|
186
|
-
|
177
|
+
begin
|
178
|
+
proxy.send(@method)
|
179
|
+
rescue Exception
|
180
|
+
$!
|
187
181
|
end
|
188
|
-
|
189
|
-
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should return successful method response" do
|
185
|
+
@execute_result.message.should == 'an error'
|
190
186
|
end
|
191
187
|
end
|
188
|
+
|
189
|
+
## Unable to repro after switch to using ThreadPool instead of work_queue gem
|
190
|
+
# context "with multiple threads making calls to proxy before worker executed" do
|
191
|
+
# it "should not deadlock" do # note, this was deadlocking when using CV#signal instead of CV#broadcast
|
192
|
+
# Parallizer::WORK_QUEUE_SIZE.times do
|
193
|
+
# Parallizer::ThreadPool.get do
|
194
|
+
# sleep(2)
|
195
|
+
# end
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# # setup the proxy
|
199
|
+
# parallizer = Parallizer.new(TestObject.new)
|
200
|
+
# parallizer.add.another_method
|
201
|
+
# proxy = parallizer.create_proxy
|
202
|
+
#
|
203
|
+
# Thread.new do
|
204
|
+
# proxy.another_method # call in another thread must happen before call in main thread for it to deadlock
|
205
|
+
# end
|
206
|
+
# sleep(1)
|
207
|
+
# proxy.another_method
|
208
|
+
# end
|
209
|
+
# end
|
192
210
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: rake
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
22
|
-
type: :
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: rspec
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- lib/parallizer.rb
|
76
76
|
- lib/parallizer/method_call_notifier.rb
|
77
77
|
- lib/parallizer/proxy.rb
|
78
|
+
- lib/parallizer/thread_pool.rb
|
78
79
|
- lib/parallizer/version.rb
|
79
80
|
- parallizer.gemspec
|
80
81
|
- spec/parallizer/method_call_notifier_spec.rb
|
@@ -101,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
102
|
version: '0'
|
102
103
|
requirements: []
|
103
104
|
rubyforge_project: parallizer
|
104
|
-
rubygems_version: 1.8.
|
105
|
+
rubygems_version: 1.8.24
|
105
106
|
signing_key:
|
106
107
|
specification_version: 3
|
107
108
|
summary: Execute your service layer in parallel
|