parallizer 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- parallizer (0.2.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
+
@@ -1,3 +1,3 @@
1
1
  class Parallizer
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.4"
3
3
  end
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 = 10
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.work_queue.enqueue_b do
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.add_dependency 'work_queue', '~> 2.5.2'
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
@@ -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 multiple threads making calls to proxy before worker executed" do
172
- it "should not deadlock" do # note, this was deadlocking when using CV#signal instead of CV#broadcast
173
- # force our worker thread to run after two calls from other threads
174
- Parallizer::WORK_QUEUE_SIZE.times do
175
- Parallizer.work_queue.enqueue_b do
176
- sleep(2)
177
- end
178
- end
179
-
180
- # setup the proxy
181
- parallizer = Parallizer.new(TestObject.new)
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
- Thread.new do
186
- proxy.another_method # call in another thread must happen before call in main thread for it to deadlock
177
+ begin
178
+ proxy.send(@method)
179
+ rescue Exception
180
+ $!
187
181
  end
188
- sleep(1)
189
- proxy.another_method
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.3
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-16 00:00:00.000000000 Z
12
+ date: 2012-10-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: work_queue
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: 2.5.2
22
- type: :runtime
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: 2.5.2
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.21
105
+ rubygems_version: 1.8.24
105
106
  signing_key:
106
107
  specification_version: 3
107
108
  summary: Execute your service layer in parallel