concur 0.0.8 → 0.1.0

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.
@@ -21,6 +21,31 @@
21
21
  puts "pooled_duration=" + pooled_duration.to_s
22
22
  executor.shutdown
23
23
 
24
+ ## EventMachine / Non-blocking I/O
25
+
26
+ Perhaps more important/interesting these days is EventMachine/non-blocking io. When your program is io bound you can
27
+ get similar performance (if not better) on a single thread as you can with multi-threads.
28
+
29
+ # Create an EventMachineExecutor
30
+ executor = Concur::Executor.new_eventmachine_executor()
31
+
32
+ # Now fire off a bunch of http requests
33
+ futures = []
34
+ TestConcur.urls.each do |url|
35
+ params_to_send = {}
36
+ params_to_send[:base_url] = url
37
+ params_to_send[:path] = "/"
38
+ params_to_send[:http_method] = :get
39
+ futures << executor.http_request(params_to_send)
40
+ end
41
+ futures.each do |f|
42
+ puts 'got=' + f.get.inspect
43
+ assert f.get.status >= 200 && f.get.status < 400
44
+ end
45
+
46
+
47
+ See https://github.com/appoxy/concur/blob/master/test/test_concur.rb for more examples.
48
+
24
49
  ## Futures
25
50
 
26
51
  A Future is what is returned from the execute method. Call `future.get` to get the results of the block
@@ -1,5 +1,6 @@
1
1
 
2
2
  require_relative 'executor'
3
+ require_relative 'thread_pool'
3
4
 
4
5
  require 'logger'
5
6
  module Concur
@@ -1,39 +1,81 @@
1
1
  require 'faraday'
2
2
  require_relative 'runnable'
3
3
  require_relative 'future'
4
- require_relative 'thread_pool'
5
4
 
6
5
  module Concur
7
6
 
8
-
9
7
  # Decouples task submission from how each task is run. An Executor can be backed by a thread pool or some
10
8
  # other mechanism, but how you use the Executor won't change. This allows you to change the backend implementation
11
9
  # with minor code changes.
12
10
  #
13
11
  # Inspired by java.util.concurrent.Executor
14
- class Executor
12
+ module Executor
13
+
14
+ class Base
15
+ def initialize(options={})
16
+
17
+ end
18
+
19
+
20
+ def shutdown
21
+
22
+ end
15
23
 
16
- attr_accessor :thread_pool
24
+ def execute
25
+ raise "execute() not implemented, this is an invalid implemention."
26
+ end
27
+
28
+ def http_request(params, &blk)
29
+
30
+ f = StandardFuture.new do
31
+ conn = Faraday.new(:url => params[:base_url]) do |builder|
32
+ # builder.use Faraday::Request::UrlEncoded # convert request params as "www-form-urlencoded"
33
+ # builder.use Faraday::Request::JSON # encode request params as json
34
+ # builder.use Faraday::Response::Logger # log the request to STDOUT
35
+ builder.use Faraday::Adapter::NetHttp # make http requests with Net::HTTP
36
+ #
37
+ # # or, use shortcuts:
38
+ # builder.request :url_encoded
39
+ # builder.request :json
40
+ # builder.response :logger
41
+ # builder.adapter :net_http
42
+ end
43
+ if params[:http_method] == :post
44
+ response = conn.post params[:path]
45
+ else
46
+ response = conn.get params[:path]
47
+ end
48
+ if block_given?
49
+ response = blk.call(response)
50
+ end
51
+ response
52
+ end
53
+ @thread_pool.process(f)
54
+ f
55
+ end
17
56
 
18
- def initialize(options={})
19
57
 
58
+ def queue_size
59
+ 0
60
+ end
20
61
  end
21
62
 
63
+
22
64
  def self.new_single_threaded_executor(options={})
23
- executor = Executor.new
24
- executor.thread_pool = SingleThreaded.new
65
+ #executor = Executor.new
66
+ executor = SingleThreaded.new
25
67
  executor
26
68
  end
27
69
 
28
70
  def self.new_multi_threaded_executor(options={})
29
- executor = Executor.new
30
- executor.thread_pool = MultiThreaded.new
71
+ #executor = Executor.new
72
+ executor = MultiThreaded.new
31
73
  executor
32
74
  end
33
75
 
34
76
  def self.new_thread_pool_executor(max_size, options={})
35
- executor = Executor.new
36
- executor.thread_pool = ThreadPool.new(max_size)
77
+ #executor = Executor.new
78
+ executor = ThreadPool.new(max_size)
37
79
  executor
38
80
  end
39
81
 
@@ -50,60 +92,26 @@ module Concur
50
92
  executor
51
93
  end
52
94
 
53
- def execute(runnable=nil, &blk)
54
- f = StandardFuture.new(runnable, &blk)
55
- @thread_pool.process(f)
56
- f
57
- end
58
-
59
- def shutdown
60
- @thread_pool.shutdown
61
- end
62
-
63
- def http_request(params, &blk)
64
-
65
- f = StandardFuture.new do
66
- conn = Faraday.new(:url => params[:base_url]) do |builder|
67
- # builder.use Faraday::Request::UrlEncoded # convert request params as "www-form-urlencoded"
68
- # builder.use Faraday::Request::JSON # encode request params as json
69
- # builder.use Faraday::Response::Logger # log the request to STDOUT
70
- builder.use Faraday::Adapter::NetHttp # make http requests with Net::HTTP
71
- #
72
- # # or, use shortcuts:
73
- # builder.request :url_encoded
74
- # builder.request :json
75
- # builder.response :logger
76
- # builder.adapter :net_http
77
- end
78
- if params[:http_method] == :post
79
- response = conn.post params[:path]
80
- else
81
- response = conn.get params[:path]
82
- end
83
- if block_given?
84
- response = blk.call(response)
85
- end
86
- response
87
- end
88
- @thread_pool.process(f)
89
- f
90
- end
91
-
92
95
 
93
96
  end
94
97
 
95
98
 
96
99
  # todo: should maybe have these backends extend Executor and just override what's necessary
97
- class SingleThreaded
100
+ class SingleThreaded < Executor::Base
98
101
  def process(f)
99
102
  f.call
100
103
  end
101
104
 
105
+ def execute(f)
106
+ process(f)
107
+ end
108
+
102
109
  def shutdown
103
110
  end
104
111
  end
105
112
 
106
- class MultiThreaded
113
+ # Spins off a new thread per job
114
+ class MultiThreaded < Executor::Base
107
115
  def process(f)
108
116
  @thread = Thread.new do
109
117
  f.thread = @thread
@@ -111,6 +119,10 @@ module Concur
111
119
  end
112
120
  end
113
121
 
122
+ def execute(f)
123
+ process(f)
124
+ end
125
+
114
126
  def shutdown
115
127
 
116
128
  end
@@ -2,7 +2,7 @@ require 'eventmachine'
2
2
  require_relative '../futures/event_machine_future'
3
3
 
4
4
  module Concur
5
- class EventMachineExecutor
5
+ class EventMachineExecutor < Executor::Base
6
6
 
7
7
  def initialize
8
8
  unless EventMachine.reactor_running? # also check EventMachine.reactor_thread? ??
@@ -28,12 +28,12 @@ module Concur
28
28
  end
29
29
 
30
30
  def run
31
- puts 'running StandardFuture'
31
+ #Concur.logger.debug 'running StandardFuture'
32
32
  begin
33
33
  @result = @callable.call
34
- puts 'callable called: ' + @result.inspect
34
+ Concur.logger.debug 'callable result: ' + @result.inspect
35
35
  rescue Exception => ex
36
- puts 'error occurred'
36
+ Concur.logger.debug "Error occurred! #{ex.class.name}: #{ex.message}"
37
37
  @ex = ex
38
38
  end
39
39
  @mutex.synchronize do # do we even need to synchronize? run should only ever be called once
@@ -2,13 +2,16 @@ require 'thread'
2
2
  begin
3
3
  require 'fastthread'
4
4
  rescue LoadError
5
- $stderr.puts "Using the ruby-core thread implementation"
5
+ # $stderr.puts "Using the ruby-core thread implementation"
6
6
  end
7
7
 
8
8
  module Concur
9
9
 
10
10
  # Another example is here: # from: http://stackoverflow.com/questions/81788/deadlock-in-threadpool
11
- class ThreadPool
11
+ class ThreadPool < Executor::Base
12
+
13
+ attr_reader :queue
14
+
12
15
  def initialize(max_size)
13
16
  @max_size = max_size
14
17
  # @thread_queue = SizedQueue.new(max_size)
@@ -24,12 +27,20 @@ module Concur
24
27
  @running = false
25
28
  end
26
29
 
30
+
27
31
  def process(callable, &blk)
28
32
  callable = blk if block_given?
29
33
  @queue.push(callable)
30
34
  start_thread
31
35
  end
32
36
 
37
+ def execute(runnable=nil, &blk)
38
+ f = StandardFuture.new(runnable, &blk)
39
+ process(f)
40
+ f
41
+ end
42
+
43
+
33
44
  def start_thread
34
45
  @mutex.synchronize do
35
46
  if !@queue.empty? && @threads.size <= @max_size
@@ -47,6 +58,12 @@ module Concur
47
58
  end
48
59
  end
49
60
 
61
+
62
+ def queue_size
63
+ @queue.size
64
+ end
65
+
66
+
50
67
  class UberThread < Thread
51
68
 
52
69
  def initialize
@@ -58,5 +75,4 @@ module Concur
58
75
  end
59
76
 
60
77
 
61
-
62
78
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: concur
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.8
5
+ version: 0.1.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Travis Reeder
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-23 00:00:00 Z
13
+ date: 2011-11-05 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: eventmachine
@@ -45,6 +45,39 @@ dependencies:
45
45
  version: "0"
46
46
  type: :runtime
47
47
  version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: eventmachine
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :runtime
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: em-http-request
61
+ prerelease: false
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ type: :runtime
69
+ version_requirements: *id005
70
+ - !ruby/object:Gem::Dependency
71
+ name: faraday
72
+ prerelease: false
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ type: :runtime
80
+ version_requirements: *id006
48
81
  description: A concurrency library for Ruby inspired by java.util.concurrency. By http://www.appoxy.com
49
82
  email: travis@appoxy.com
50
83
  executables: []
@@ -89,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
122
  requirements: []
90
123
 
91
124
  rubyforge_project:
92
- rubygems_version: 1.7.2
125
+ rubygems_version: 1.8.8
93
126
  signing_key:
94
127
  specification_version: 3
95
128
  summary: A concurrency library for Ruby inspired by java.util.concurrency. By http://www.appoxy.com