concur 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1 +1,29 @@
1
- # Concur - A concurrency library for Ruby inspired by java.util.concurrency
1
+ # Concur - A concurrency library for Ruby inspired by java.util.concurrency
2
+
3
+ ## General Usage
4
+
5
+ # Choose which executor you want, there are several to choose from
6
+ executor = Concur::Executor.new_thread_pool_executor(10)
7
+ start_time = Time.now
8
+
9
+ jobs = []
10
+ times.times do |i|
11
+ future = executor.execute do
12
+ puts "hello #{i}"
13
+ "result #{i}"
14
+ end
15
+ jobs << future
16
+ end
17
+ jobs.each do |j|
18
+ puts "uber fast result=#{j.get}"
19
+ end
20
+ pooled_duration = Time.now - start_time
21
+ puts "pooled_duration=" + pooled_duration.to_s
22
+ executor.shutdown
23
+
24
+ ## Futures
25
+
26
+ A Future is what is returned from the execute method. Call `future.get` to get the results of the block
27
+ or the Callable object. If it's not finished, `get` will block until it is. `get` will also raise an Exception
28
+ if an Exception occurred during running.
29
+
data/lib/concur.rb CHANGED
@@ -1,15 +1,15 @@
1
-
2
- require_relative 'executor'
3
-
4
- require 'logger'
5
- module Concur
6
- @@logger = Logger.new(STDOUT)
7
-
8
- def self.logger
9
- @@logger
10
- end
11
- def self.logger=(logger)
12
- @@logger = logger
13
- end
14
-
1
+
2
+ require_relative 'executor'
3
+
4
+ require 'logger'
5
+ module Concur
6
+ @@logger = Logger.new(STDOUT)
7
+
8
+ def self.logger
9
+ @@logger
10
+ end
11
+ def self.logger=(logger)
12
+ @@logger = logger
13
+ end
14
+
15
15
  end
data/lib/executor.rb CHANGED
@@ -1,73 +1,86 @@
1
- require_relative 'runnable'
2
- require_relative 'future'
3
- require_relative 'thread_pool'
4
-
5
-
6
- module Concur
7
-
8
-
9
- # Decouples task submission from how each task is run. An Executor can be backed by a thread pool or some
10
- # other mechanism, but how you use the Executor won't change. This allows you to change the backend implementation
11
- # with minor code changes.
12
- #
13
- # Inspired by java.util.concurrent.Executor
14
- class Executor
15
-
16
- attr_accessor :thread_pool
17
-
18
- def initialize(options={})
19
-
20
- end
21
-
22
- def self.new_single_threaded_executor(options={})
23
- executor = Executor.new
24
- executor.thread_pool = SingleThreaded.new
25
- executor
26
- end
27
-
28
- def self.new_multi_threaded_executor(options={})
29
- executor = Executor.new
30
- executor.thread_pool = MultiThreaded.new
31
- executor
32
- end
33
-
34
- def self.new_thread_pool_executor(max_size, options={})
35
- executor = Executor.new
36
- executor.thread_pool = ThreadPool.new(max_size)
37
- executor
38
- end
39
-
40
- def execute(runnable=nil, &blk)
41
- f = Future.new(runnable, &blk)
42
- @thread_pool.process(f)
43
- f
44
- end
45
-
46
- def shutdown
47
- @thread_pool.shutdown
48
- end
49
- end
50
-
51
- # todo: should maybe have these backends extend Executor and just override what's necessary
52
- class SingleThreaded
53
- def process(f)
54
- f.call
55
- end
56
-
57
- def shutdown
58
- end
59
- end
60
-
61
- class MultiThreaded
62
- def process(f)
63
- @thread = Thread.new do
64
- f.thread = @thread
65
- f.call
66
- end
67
- end
68
-
69
- def shutdown
70
-
71
- end
72
- end
73
- end
1
+ require_relative 'runnable'
2
+ require_relative 'future'
3
+ require_relative 'thread_pool'
4
+
5
+
6
+ module Concur
7
+
8
+
9
+ # Decouples task submission from how each task is run. An Executor can be backed by a thread pool or some
10
+ # other mechanism, but how you use the Executor won't change. This allows you to change the backend implementation
11
+ # with minor code changes.
12
+ #
13
+ # Inspired by java.util.concurrent.Executor
14
+ class Executor
15
+
16
+ attr_accessor :thread_pool
17
+
18
+ def initialize(options={})
19
+
20
+ end
21
+
22
+ def self.new_single_threaded_executor(options={})
23
+ executor = Executor.new
24
+ executor.thread_pool = SingleThreaded.new
25
+ executor
26
+ end
27
+
28
+ def self.new_multi_threaded_executor(options={})
29
+ executor = Executor.new
30
+ executor.thread_pool = MultiThreaded.new
31
+ executor
32
+ end
33
+
34
+ def self.new_thread_pool_executor(max_size, options={})
35
+ executor = Executor.new
36
+ executor.thread_pool = ThreadPool.new(max_size)
37
+ executor
38
+ end
39
+
40
+ def self.new_eventmachine_executor()
41
+ require_relative 'executors/event_machine_executor'
42
+ executor = EventMachineExecutor.new()
43
+ executor
44
+ end
45
+
46
+ # NOT WORKING
47
+ def self.new_neverblock_executor(max_size)
48
+ require_relative 'executors/never_block_executor'
49
+ executor = NeverBlockExecutor.new(max_size)
50
+ executor
51
+ end
52
+
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
+ end
63
+
64
+ # todo: should maybe have these backends extend Executor and just override what's necessary
65
+ class SingleThreaded
66
+ def process(f)
67
+ f.call
68
+ end
69
+
70
+ def shutdown
71
+ end
72
+ end
73
+
74
+ class MultiThreaded
75
+ def process(f)
76
+ @thread = Thread.new do
77
+ f.thread = @thread
78
+ f.call
79
+ end
80
+ end
81
+
82
+ def shutdown
83
+
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,34 @@
1
+ require 'eventmachine'
2
+ require_relative '../futures/event_machine_future'
3
+
4
+ module Concur
5
+ class EventMachineExecutor
6
+
7
+
8
+ def initialize
9
+ @futures = []
10
+ @em_thread = Thread.new do
11
+ EventMachine.run do
12
+ puts 'Starting EventMachineExecutor...'
13
+ # @futures.each do |f|
14
+ #
15
+ # end
16
+ end
17
+ puts 'EventMachine loop done'
18
+ end
19
+ end
20
+
21
+ def execute(runnable=nil, &blk)
22
+ f = EventMachineFuture.new(runnable, &blk)
23
+ # @futures = f
24
+ EventMachine.schedule(f)
25
+ f
26
+ end
27
+
28
+ def shutdown
29
+ @em_thread.kill
30
+ puts 'shutdown'
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+
2
+ require 'neverblock'
3
+
4
+ # This doesn't work as expected. Not sure how to get it to non block on the IO calls
5
+
6
+ module Concur
7
+ class NeverBlockExecutor
8
+
9
+ def initialize(max_size)
10
+ @fiber_pool = NeverBlock::Pool::FiberPool.new(max_size)
11
+ end
12
+
13
+ def execute(runnable=nil, &blk)
14
+ f = Future.new(runnable, &blk)
15
+ @fiber_pool.spawn do
16
+ puts 'running in spawn'
17
+ f.call
18
+ end
19
+ f
20
+ end
21
+
22
+ def shutdown
23
+
24
+ end
25
+
26
+ end
27
+ end
data/lib/future.rb CHANGED
@@ -1,53 +1,64 @@
1
- module Concur
2
-
3
- #An Future is a class that captures the results of a threaded object so you can retreive the results later.
4
- #This is what is returned from Executors.
5
- class Future
6
- attr_accessor :thread
7
-
8
- def initialize(runnable=nil, &block)
9
-
10
- @mutex = Mutex.new
11
- @cv = ConditionVariable.new
12
- @callable = runnable
13
- if block_given?
14
- @callable = block
15
- end
16
-
17
- end
18
-
19
- def run
20
- begin
21
- @result = @callable.call
22
- rescue Exception => ex
23
- @ex = ex
24
- end
25
- @mutex.synchronize do # do we even need to synchronize? run should only ever be called once
26
- @complete = true
27
- @cv.broadcast
28
- end
29
- end
30
-
31
- def call
32
- run
33
- end
34
-
35
- def complete?
36
- @complete
37
- end
38
-
39
- # Returns results. Will wait for thread to complete execution if not already complete.
40
- def get
41
- # @thread.value
42
- @mutex.synchronize do
43
- unless @complete
44
- @cv.wait(@mutex)
45
- end
46
- end
47
- if @ex
48
- raise @ex
49
- end
50
- @result
51
- end
52
- end
53
- end
1
+ #An Future is a class that captures the results of a threaded object so you can retrieve the results later.
2
+ #This is what is returned from Executors.
3
+ #
4
+ # This particular Future can be used for synchronous blocks / runnables / callables that are run in a separate thread.
5
+
6
+ module Concur
7
+
8
+ module Future
9
+ def future?
10
+ true
11
+ end
12
+ end
13
+
14
+ class StandardFuture
15
+ include Future
16
+
17
+ attr_accessor :thread, :ex
18
+
19
+ def initialize(runnable=nil, &block)
20
+
21
+ @mutex = Mutex.new
22
+ @cv = ConditionVariable.new
23
+ @callable = runnable
24
+ if block_given?
25
+ @callable = block
26
+ end
27
+
28
+ end
29
+
30
+ def run
31
+ begin
32
+ @result = @callable.call
33
+ rescue Exception => ex
34
+ @ex = ex
35
+ end
36
+ @mutex.synchronize do # do we even need to synchronize? run should only ever be called once
37
+ @complete = true
38
+ @cv.broadcast
39
+ end
40
+ end
41
+
42
+ def call
43
+ run
44
+ end
45
+
46
+ def complete?
47
+ @complete
48
+ end
49
+
50
+ # Returns results. Will wait for thread to complete execution if not already complete.
51
+ def get
52
+ # @thread.value
53
+ @mutex.synchronize do
54
+ unless @complete
55
+ @cv.wait(@mutex)
56
+ end
57
+ end
58
+ if @ex
59
+ raise @ex
60
+ end
61
+ @result
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,164 @@
1
+ # This future enables a blocking get for a result from EventMachine HTTP request.
2
+
3
+ module Concur
4
+
5
+ class EventMachineError < StandardError
6
+
7
+ def initialize(callbackable)
8
+ super("Error in #{callbackable.class.name}")
9
+ @callbackable = callbackable
10
+
11
+ end
12
+ end
13
+
14
+ class EventMachineFutureCallback
15
+
16
+ def future?
17
+ true
18
+ end
19
+
20
+ attr_accessor :errblk, :callblk
21
+
22
+ def initialize(callbackable, &block)
23
+ puts 'EventMachineFutureCallback.initialize: ' + callbackable.inspect
24
+ @callbackable = callbackable
25
+ if block_given?
26
+ @callblk = block
27
+ end
28
+ end
29
+
30
+ def run
31
+
32
+ # http = @callbackable
33
+ # http.errback {
34
+ # @ex = EventMachineError.new(http)
35
+ # complete
36
+ # }
37
+ # http.callback {
38
+ # if @callback
39
+ # @callback.call(@callbackable)
40
+ # end
41
+ # complete
42
+ # }
43
+
44
+
45
+ end
46
+ def errback &blk
47
+ @errblk = blk
48
+ end
49
+
50
+ def callback &blk
51
+ @callblk = blk
52
+ end
53
+
54
+ def errback2 &blk
55
+ puts 'EventMachineFutureCallback.errback'
56
+ proc = Proc.new do
57
+ puts 'errback proc'
58
+ blk.call(@callbackable)
59
+ end
60
+ puts 'setting errback on ' + @callbackable.inspect
61
+ @callbackable.errback &proc
62
+ puts 'errback set'
63
+ end
64
+
65
+ def callback2 &blk
66
+ puts 'EventMachineFutureCallback.callback'
67
+ proc = Proc.new do
68
+ @result = []
69
+ if @callblk
70
+ @result = @callblk.call(@callbackable)
71
+ end
72
+ blk.call(@result)
73
+ end
74
+ @callbackable.callback &proc
75
+ end
76
+ #
77
+ # def call_callback(response)
78
+ # puts 'call_callback=' + response.inspect
79
+ # return unless callblk
80
+ # callblk.call(response)
81
+ # end
82
+ #
83
+ # def call_errback(response)
84
+ # return unless errblk
85
+ # errblk.call(response)
86
+ # end
87
+ end
88
+
89
+ class EventMachineFuture
90
+ include Concur::Future
91
+
92
+ attr_accessor :ex,:result
93
+
94
+ def initialize(callable, &block)
95
+
96
+ @mutex = Mutex.new
97
+ @cv = ConditionVariable.new
98
+ @callable = callable
99
+ if block_given?
100
+ @callable = block
101
+ end
102
+ end
103
+
104
+
105
+ def run
106
+ puts 'EMFuture.run'
107
+ p @callable
108
+ begin
109
+ @callbackable = @callable.call
110
+ puts 'done @callable.call ' + @callbackable.inspect
111
+ rescue Exception => ex
112
+ @ex = ex
113
+ end
114
+ if @ex
115
+ complete
116
+ return
117
+ end
118
+
119
+ http = @callbackable
120
+ http.errback2 {
121
+ puts 'completion errback'
122
+ @ex = EventMachineError.new(http)
123
+ complete
124
+ }
125
+ @result = (http.callback2 {|result|
126
+ @result = result
127
+ complete
128
+ })
129
+ puts '@result=' + @result.inspect
130
+
131
+ end
132
+
133
+ def call
134
+ run
135
+ end
136
+
137
+ def complete
138
+ @complete = true
139
+ end
140
+
141
+
142
+ def complete?
143
+ @complete
144
+ end
145
+
146
+ # Returns results. Will wait for thread to complete execution if not already complete.
147
+ def get
148
+ # @thread.value
149
+ while not @complete
150
+ # todo: gotta be a better way
151
+ puts 'sleeping'
152
+ sleep 0.5
153
+ end
154
+ return get_response
155
+ end
156
+
157
+ def get_response
158
+ if @ex
159
+ raise @ex
160
+ end
161
+ @result
162
+ end
163
+ end
164
+ end
data/lib/runnable.rb CHANGED
@@ -1,13 +1,13 @@
1
-
2
- # A mixin for runnable classes.
3
- module Concur
4
- module Runnable
5
- def run
6
- raise "No run method defined in your runable!"
7
- end
8
-
9
- def call
10
- run
11
- end
12
- end
13
- end
1
+
2
+ # A mixin for runnable classes.
3
+ module Concur
4
+ module Runnable
5
+ def run
6
+ raise "No run method defined in your runable!"
7
+ end
8
+
9
+ def call
10
+ run
11
+ end
12
+ end
13
+ end
data/lib/thread_pool.rb CHANGED
@@ -1,62 +1,62 @@
1
- require 'thread'
2
- begin
3
- require 'fastthread'
4
- rescue LoadError
5
- $stderr.puts "Using the ruby-core thread implementation"
6
- end
7
-
8
- module Concur
9
-
10
- # Another example is here: # from: http://stackoverflow.com/questions/81788/deadlock-in-threadpool
11
- class ThreadPool
12
- def initialize(max_size)
13
- @max_size = max_size
14
- # @thread_queue = SizedQueue.new(max_size)
15
- @running = true
16
- @mutex = Mutex.new
17
- @cv = ConditionVariable.new
18
- @queue = Queue.new
19
- @threads = []
20
-
21
- end
22
-
23
- def shutdown
24
- @running = false
25
- end
26
-
27
- def process(callable, &blk)
28
- callable = blk if block_given?
29
- @queue.push(callable)
30
- start_thread
31
- end
32
-
33
- def start_thread
34
- @mutex.synchronize do
35
- if !@queue.empty? && @threads.size <= @max_size
36
- t = UberThread.new do
37
- while @running
38
- f = @queue.pop
39
- f.thread = t
40
- f.call
41
- end
42
- # Concur.logger.info "Thread dying " + t.inspect
43
- end
44
- Concur.logger.debug "Created new thread " + t.inspect
45
- @threads << t
46
- end
47
- end
48
- end
49
-
50
- class UberThread < Thread
51
-
52
- def initialize
53
- super
54
- end
55
-
56
- end
57
-
58
- end
59
-
60
-
61
-
62
- end
1
+ require 'thread'
2
+ begin
3
+ require 'fastthread'
4
+ rescue LoadError
5
+ $stderr.puts "Using the ruby-core thread implementation"
6
+ end
7
+
8
+ module Concur
9
+
10
+ # Another example is here: # from: http://stackoverflow.com/questions/81788/deadlock-in-threadpool
11
+ class ThreadPool
12
+ def initialize(max_size)
13
+ @max_size = max_size
14
+ # @thread_queue = SizedQueue.new(max_size)
15
+ @running = true
16
+ @mutex = Mutex.new
17
+ @cv = ConditionVariable.new
18
+ @queue = Queue.new
19
+ @threads = []
20
+
21
+ end
22
+
23
+ def shutdown
24
+ @running = false
25
+ end
26
+
27
+ def process(callable, &blk)
28
+ callable = blk if block_given?
29
+ @queue.push(callable)
30
+ start_thread
31
+ end
32
+
33
+ def start_thread
34
+ @mutex.synchronize do
35
+ if !@queue.empty? && @threads.size <= @max_size
36
+ t = UberThread.new do
37
+ while @running
38
+ f = @queue.pop
39
+ f.thread = t
40
+ f.call
41
+ end
42
+ # Concur.logger.info "Thread dying " + t.inspect
43
+ end
44
+ Concur.logger.debug "Created new thread " + t.inspect
45
+ @threads << t
46
+ end
47
+ end
48
+ end
49
+
50
+ class UberThread < Thread
51
+
52
+ def initialize
53
+ super
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+
61
+
62
+ end
@@ -1,82 +1,87 @@
1
- require 'rspec'
2
-
3
- require_relative '../lib/concur'
4
- require_relative 'job'
5
-
6
- describe Concur::Executor do
7
- describe "#score" do
8
- it "runs faster in parallel" do
9
- times = 10
10
-
11
- job = Job.new(1)
12
- puts 'runnable? ' + job.is_a?(Concur::Runnable).to_s
13
- start_time = Time.now
14
- times.times do |i|
15
- job = Job.new(i)
16
- job.run
17
- end
18
- non_concurrent_duration = Time.now - start_time
19
- puts "duration=" + non_concurrent_duration.to_s
20
-
21
- puts '---------------'
22
-
23
- puts "Now for concurrent"
24
- executor = Concur::Executor.new_multi_threaded_executor
25
- start_time = Time.now
26
-
27
- jobs = []
28
- times.times do |i|
29
- job = Job.new(i)
30
- jobs << executor.execute(job)
31
- end
32
- jobs.each do |j|
33
- puts "uber fast result=#{j.get}"
34
- end
35
- concurrent_duration = Time.now - start_time
36
- puts "duration=" + concurrent_duration.to_s
37
-
38
- concurrent_duration.should be < (non_concurrent_duration/2)
39
-
40
- puts "Now for pooled"
41
- executor = Concur::Executor.new_thread_pool_executor(10)
42
- start_time = Time.now
43
-
44
- jobs = []
45
- times.times do |i|
46
- job = Job.new(i)
47
- future = executor.execute(job)
48
- jobs << future
49
- end
50
- jobs.each do |j|
51
- puts "uber fast result=#{j.get}"
52
- end
53
- pooled_duration = Time.now - start_time
54
- puts "pooled_duration=" + pooled_duration.to_s
55
-
56
- pooled_duration.should be < (non_concurrent_duration/2)
57
- # pooled_duration.should_be > concurrent_duration
58
-
59
- executor.shutdown
60
-
61
- end
62
- end
63
- end
64
-
65
- describe Concur::Future do
66
-
67
- describe "#new" do
68
-
69
- it "can accept blocks" do
70
- future = Concur::Future.new do
71
- puts "i'm in the block"
72
- "result of block"
73
- end
74
- puts 'get=' + future.get
75
- future.get.should == "result of block"
76
- end
77
-
78
- end
79
-
80
- end
81
-
82
-
1
+ require 'rspec'
2
+ require 'neverblock'
3
+
4
+ require_relative '../lib/concur'
5
+ require_relative 'job'
6
+
7
+ @@durations = []
8
+
9
+ def run_jobs(name, executor, times, options={})
10
+ puts "Running #{name}..."
11
+ start_time = Time.now
12
+
13
+ jobs = []
14
+ times.times do |i|
15
+ job = Job.new(i, options)
16
+ jobs << executor.execute(job)
17
+ end
18
+ jobs.each do |j|
19
+ puts "result=#{j.get}"
20
+ end
21
+ concurrent_duration = Time.now - start_time
22
+ o = "#{name} duration=" + concurrent_duration.to_s
23
+ puts o
24
+ @@durations << o
25
+ concurrent_duration
26
+ end
27
+
28
+ describe Concur::Executor do
29
+ describe "#score" do
30
+ it "runs faster in parallel" do
31
+ times = 10
32
+
33
+ job = Job.new(1)
34
+ puts 'runnable? ' + job.is_a?(Concur::Runnable).to_s
35
+ non_concurrent_duration = 0
36
+ #
37
+ executor = Concur::Executor.new_single_threaded_executor
38
+ non_concurrent_duration =run_jobs("non concurrent", executor, times)
39
+ executor.shutdown
40
+
41
+ executor = Concur::Executor.new_multi_threaded_executor
42
+ concurrent_duration = run_jobs("multi thread", executor, times)
43
+ concurrent_duration.should be < (non_concurrent_duration/2)
44
+ executor.shutdown
45
+
46
+ executor = Concur::Executor.new_thread_pool_executor(10)
47
+ pooled_duration = run_jobs("thread pool", executor, times)
48
+ pooled_duration.should be < (non_concurrent_duration/2)
49
+ executor.shutdown
50
+
51
+ # Don't think I know how to use NeverBlock properly
52
+ # executor = Concur::Executor.new_neverblock_executor(10)
53
+ # neverblock_duration = run_jobs("never blocked", executor, times)
54
+ # neverblock_duration.should be < (non_concurrent_duration/2)
55
+ # executor.shutdown
56
+
57
+ executor = Concur::Executor.new_eventmachine_executor()
58
+ em_duration = run_jobs("eventmachine", executor, times, :em=>true)
59
+ em_duration.should be < (non_concurrent_duration/2)
60
+ executor.shutdown
61
+
62
+ @@durations.each do |s|
63
+ puts s
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+
70
+ describe Concur::Future do
71
+
72
+ describe "#new" do
73
+
74
+ it "can accept blocks" do
75
+ future = Concur::Future.new do
76
+ puts "i'm in the block"
77
+ "result of block"
78
+ end
79
+ puts 'get=' + future.get
80
+ future.get.should == "result of block"
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
87
+
data/test/job.rb CHANGED
@@ -1,16 +1,51 @@
1
- require_relative '../lib/runnable'
2
-
3
- class Job
4
- include Concur::Runnable
5
-
6
- def initialize(i)
7
- @i = i
8
- end
9
-
10
- def run
11
- sleep 3
12
- puts "Finished #{@i}"
13
- "response #{@i}"
14
- end
15
-
1
+ require_relative '../lib/runnable'
2
+ require 'rest-client'
3
+ require 'eventmachine'
4
+
5
+ class Job
6
+ include Concur::Runnable
7
+
8
+ def initialize(i, options={})
9
+ @i = i
10
+ if options[:em]
11
+ @em = true
12
+ end
13
+ end
14
+
15
+ def em_request(url)
16
+ puts 'emrequest for ' + url
17
+ http = EventMachine::Protocols::HttpClient.request(
18
+ :host => url,
19
+ :port => 80,
20
+ :request => "/"
21
+ )
22
+ http.callback { |response|
23
+ puts response[:status]
24
+ puts response[:headers]
25
+ puts response[:content]
26
+ }
27
+ end
28
+
29
+ def run
30
+ puts "Starting #{@i}... em? #{@em}"
31
+ # sleep 1
32
+ urls = ["www.yahoo.com", "www.microsoft.com"] # , "www.github.com"
33
+ if @em
34
+ urls.each do |u|
35
+ em_request(u)
36
+ end
37
+ else
38
+ urls.each do |u|
39
+ get(u)
40
+ end
41
+ end
42
+ puts "Finished #{@i}"
43
+ "response #{@i}"
44
+ end
45
+
46
+ def get(url)
47
+ puts 'getting ' + url
48
+ RestClient.get "http://#{url}"
49
+ end
50
+
16
51
  end
metadata CHANGED
@@ -1,69 +1,65 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: concur
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.4
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
5
+ version: 0.0.6
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Travis Reeder
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-03-10 00:00:00.000000000 -08:00
13
- default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: rspec
17
- requirement: &25999668 !ruby/object:Gem::Requirement
18
- none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
22
- version: '0'
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: *25999668
26
- description: A concurrency library for Ruby inspired by java.util.concurrency. By
27
- http://www.appoxy.com
12
+
13
+ date: 2011-05-02 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: A concurrency library for Ruby inspired by java.util.concurrency. By http://www.appoxy.com
28
17
  email: travis@appoxy.com
29
18
  executables: []
19
+
30
20
  extensions: []
31
- extra_rdoc_files:
21
+
22
+ extra_rdoc_files:
32
23
  - README.markdown
33
- files:
24
+ files:
34
25
  - lib/concur.rb
35
26
  - lib/executor.rb
27
+ - lib/executors/event_machine_executor.rb
28
+ - lib/executors/never_block_executor.rb
36
29
  - lib/future.rb
30
+ - lib/futures/event_machine_future.rb
37
31
  - lib/runnable.rb
38
32
  - lib/thread_pool.rb
39
33
  - README.markdown
40
34
  - test/executor_spec.rb
41
35
  - test/job.rb
42
- has_rdoc: true
43
36
  homepage: http://github.com/appoxy/concur/
44
37
  licenses: []
38
+
45
39
  post_install_message:
46
40
  rdoc_options: []
47
- require_paths:
41
+
42
+ require_paths:
48
43
  - lib
49
- required_ruby_version: !ruby/object:Gem::Requirement
44
+ required_ruby_version: !ruby/object:Gem::Requirement
50
45
  none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
51
  none: false
57
- requirements:
58
- - - ! '>='
59
- - !ruby/object:Gem::Version
60
- version: '0'
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
61
56
  requirements: []
57
+
62
58
  rubyforge_project:
63
- rubygems_version: 1.6.2
59
+ rubygems_version: 1.7.2
64
60
  signing_key:
65
61
  specification_version: 3
66
62
  summary: A concurrency library for Ruby inspired by java.util.concurrency. By http://www.appoxy.com
67
- test_files:
63
+ test_files:
68
64
  - test/executor_spec.rb
69
65
  - test/job.rb