parallizer 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- parallizer (0.2.3)
5
- work_queue (~> 2.5.2)
4
+ parallizer (0.3.0)
5
+ work_queue
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
@@ -9,31 +9,18 @@ class Parallizer
9
9
  end
10
10
 
11
11
  def method_missing(name, *args, &block)
12
- value = nil
13
-
14
12
  if call_info = @call_infos[[name, *args]]
15
- call_info[:mutex].synchronize do
16
- if !call_info[:complete?]
17
- # not done, so lets wait for signal of completion
18
- call_info[:condition_variable].wait(call_info[:mutex])
19
- end
20
- # we now have our result from the worker thread
21
-
22
- if call_info[:exception]
23
- # add the current call stack to the exception backtrace
24
- exception = call_info[:exception].clone
25
- exception.set_backtrace((call_info[:exception].backtrace || []) + caller)
26
- raise exception
27
- end
28
-
29
- value = call_info[:result]
13
+ if call_info[:exception]
14
+ # add the current call stack to the exception backtrace
15
+ exception = call_info[:exception].clone
16
+ exception.set_backtrace((call_info[:exception].backtrace || []) + caller)
17
+ raise exception
18
+ else
19
+ call_info[:result]
30
20
  end
31
21
  else
32
- # pass through to client since not added
33
- value = @client.send(*[name, *args], &block)
22
+ @client.send(*[name, *args], &block)
34
23
  end
35
-
36
- value
37
24
  end
38
25
 
39
26
  def respond_to?(name, include_private = false, &block)
@@ -1,3 +1,3 @@
1
1
  class Parallizer
2
- VERSION = "0.2.4"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/parallizer.rb CHANGED
@@ -1,10 +1,10 @@
1
+ require 'work_queue'
1
2
  require 'parallizer/version'
2
3
  require 'parallizer/proxy'
3
4
  require 'parallizer/method_call_notifier'
4
- require 'parallizer/thread_pool'
5
5
 
6
6
  class Parallizer
7
- WORK_QUEUE_SIZE = Parallizer::ThreadPool::THEAD_POOL_SIZE
7
+ WORK_QUEUE_SIZE = 10
8
8
 
9
9
  attr_reader :calls, :call_infos, :client, :proxy, :options
10
10
 
@@ -34,42 +34,43 @@ class Parallizer
34
34
  :complete? => false,
35
35
  :result => nil,
36
36
  :exception => nil,
37
- :condition_variable => ConditionVariable.new,
38
- :mutex => Mutex.new,
39
37
  :retries => options[:retries]
40
38
  }
41
39
  call_infos[method_name_and_args] = call_info
42
-
43
- enqueue_call_info(call_info, method_name_and_args)
44
40
  end
45
41
 
46
42
  def create_proxy
47
43
  raise ArgumentError, "Cannot create another proxy" if @proxy
48
44
 
45
+ execute
46
+
49
47
  Parallizer::Proxy.new(client, call_infos)
50
48
  end
51
49
 
52
50
  private
53
51
 
54
- def enqueue_call_info(call_info, method_name_and_args)
55
- Parallizer::ThreadPool.get do
56
- call_info[:mutex].synchronize do
57
- begin
58
- (call_info[:retries] + 1).times do
59
- begin
60
- call_info[:exception] = nil # reset exception before each send attempt
61
- call_info[:result] = client.send(*method_name_and_args)
62
- break # success
63
- rescue Exception => e
64
- call_info[:exception] = e
65
- end
52
+ def self.work_queue
53
+ # TODO: share the work queue among calling threads
54
+ Thread.current[:parallizer_work_queue] ||= WorkQueue.new(WORK_QUEUE_SIZE)
55
+ end
56
+
57
+ def execute
58
+ call_infos.each do |method_name_and_args, call_info|
59
+ Parallizer.work_queue.enqueue_b do
60
+ (call_info[:retries] + 1).times do
61
+ begin
62
+ call_info[:exception] = nil # reset exception before each send attempt
63
+ call_info[:result] = client.send(*method_name_and_args)
64
+ break # success
65
+ rescue Exception => e
66
+ call_info[:exception] = e
66
67
  end
67
- ensure
68
- call_info[:complete?] = true
69
- call_info[:condition_variable].broadcast
70
- Parallizer::ThreadPool.put(Thread.current)
71
68
  end
72
69
  end
73
70
  end
71
+
72
+ Parallizer.work_queue.join
73
+
74
+ Parallizer::Proxy.new(client, call_infos)
74
75
  end
75
76
  end
data/parallizer.gemspec CHANGED
@@ -18,6 +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'
21
22
  s.add_development_dependency 'rake'
22
23
  s.add_development_dependency 'rspec', '~> 2.9.0'
23
24
  s.add_development_dependency 'always_execute', '~> 0.1.1'
@@ -29,57 +29,39 @@ describe Parallizer::Proxy do
29
29
  @call_key += [:a_method, "some value"]
30
30
  end
31
31
 
32
- context "with not complete?" do
32
+ context "with an exception" do
33
33
  before do
34
- @call_info[:complete?] = false
35
- @call_info[:condition_variable].should_receive(:wait).with(@call_info[:mutex])
36
- @call_info[:result] = 'this is a value'
34
+ @call_info[:exception] = StandardError.new('An Exception')
35
+ @call_info[:exception].set_backtrace(["/tmp/foo.rb:123:in `in a_worker_thread_method'"])
37
36
  end
38
37
 
39
- it "should return the call_info result" do
40
- @execute_result.should == @call_info[:result]
38
+ execute do
39
+ def a_calling_thread_method
40
+ call_infos = { @call_key => @call_info }
41
+ proxy = Parallizer::Proxy.new(@client, call_infos)
42
+ proxy.send(*@call_key) rescue $!
43
+ end
44
+ a_calling_thread_method
45
+ end
46
+
47
+ it "should raise exception" do
48
+ @execute_result.class.should == @call_info[:exception].class
49
+ @execute_result.message.should == @call_info[:exception].message
50
+ end
51
+
52
+ it "should append backtrace of current call" do
53
+ @execute_result.backtrace.join.should match /a_worker_thread_method/
54
+ @execute_result.backtrace.join.should match /a_calling_thread_method/
41
55
  end
42
56
  end
43
57
 
44
- context "with complete? call info" do
58
+ context "with a result" do
45
59
  before do
46
- @call_info[:complete?] = true
47
- end
48
-
49
- context "with an exception" do
50
- before do
51
- @call_info[:exception] = StandardError.new('An Exception')
52
- @call_info[:exception].set_backtrace(["/tmp/foo.rb:123:in `in a_worker_thread_method'"])
53
- end
54
-
55
- execute do
56
- def a_calling_thread_method
57
- call_infos = { @call_key => @call_info }
58
- proxy = Parallizer::Proxy.new(@client, call_infos)
59
- proxy.send(*@call_key) rescue $!
60
- end
61
- a_calling_thread_method
62
- end
63
-
64
- it "should raise exception" do
65
- @execute_result.class.should == @call_info[:exception].class
66
- @execute_result.message.should == @call_info[:exception].message
67
- end
68
-
69
- it "should append backtrace of current call" do
70
- @execute_result.backtrace.join.should match /a_worker_thread_method/
71
- @execute_result.backtrace.join.should match /a_calling_thread_method/
72
- end
60
+ @call_info[:result] = "a result"
73
61
  end
74
62
 
75
- context "with a result" do
76
- before do
77
- @call_info[:result] = "a result"
78
- end
79
-
80
- it "should return result" do
81
- @execute_result.should == @call_info[:result]
82
- end
63
+ it "should return result" do
64
+ @execute_result.should == @call_info[:result]
83
65
  end
84
66
  end
85
67
  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
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-22 00:00:00.000000000 Z
12
+ date: 2012-10-30 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: work_queue
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
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'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: rake
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -75,7 +91,6 @@ files:
75
91
  - lib/parallizer.rb
76
92
  - lib/parallizer/method_call_notifier.rb
77
93
  - lib/parallizer/proxy.rb
78
- - lib/parallizer/thread_pool.rb
79
94
  - lib/parallizer/version.rb
80
95
  - parallizer.gemspec
81
96
  - spec/parallizer/method_call_notifier_spec.rb
@@ -94,12 +109,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
94
109
  - - ! '>='
95
110
  - !ruby/object:Gem::Version
96
111
  version: '0'
112
+ segments:
113
+ - 0
114
+ hash: 4537061514701133663
97
115
  required_rubygems_version: !ruby/object:Gem::Requirement
98
116
  none: false
99
117
  requirements:
100
118
  - - ! '>='
101
119
  - !ruby/object:Gem::Version
102
120
  version: '0'
121
+ segments:
122
+ - 0
123
+ hash: 4537061514701133663
103
124
  requirements: []
104
125
  rubyforge_project: parallizer
105
126
  rubygems_version: 1.8.24
@@ -1,63 +0,0 @@
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
-