forked from eventmachine/eventmachine
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
192 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
require File.dirname(__FILE__) + '/helper' | ||
|
||
EM.run do | ||
array = (1..100).to_a | ||
|
||
tickloop = EM.tick_loop do | ||
if array.empty? | ||
:stop | ||
else | ||
puts array.shift | ||
end | ||
end | ||
|
||
tickloop.on_stop { EM.stop } | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
require File.dirname(__FILE__) + '/helper' | ||
|
||
class TickCounter | ||
attr_reader :start_time, :count | ||
|
||
def initialize | ||
reset | ||
@tick_loop = EM.tick_loop(method(:tick)) | ||
end | ||
|
||
def reset | ||
@count = 0 | ||
@start_time = EM.current_time | ||
end | ||
|
||
def tick | ||
@count += 1 | ||
end | ||
|
||
def rate | ||
@count / (EM.current_time - @start_time) | ||
end | ||
end | ||
|
||
period = 5 | ||
EM.run do | ||
counter = TickCounter.new | ||
EM.add_periodic_timer(period) do | ||
puts "Ticks per second: #{counter.rate} (mean of last #{period}s)" | ||
counter.reset | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
module EventMachine | ||
# Creates and immediately starts an EventMachine::TickLoop | ||
def self.tick_loop(*a, &b) | ||
TickLoop.new(*a, &b).start | ||
end | ||
|
||
# A TickLoop is useful when one needs to distribute amounts of work | ||
# throughout ticks in order to maintain response times. It is also useful for | ||
# simple repeated checks and metrics. | ||
# | ||
# # Here we run through an array one item per tick until it is empty, | ||
# # printing each element. | ||
# # When the array is empty, we return :stop from the callback, and the | ||
# # loop will terminate. | ||
# # When the loop terminates, the on_stop callbacks will be called. | ||
# EM.run do | ||
# array = (1..100).to_a | ||
# | ||
# tickloop = EM.tick_loop do | ||
# if array.empty? | ||
# :stop | ||
# else | ||
# puts array.shift | ||
# end | ||
# end | ||
# | ||
# tickloop.on_stop { EM.stop } | ||
# end | ||
# | ||
class TickLoop | ||
|
||
# Arguments: A callback (EM::Callback) to call each tick. If the call | ||
# returns +:stop+ then the loop will be stopped. Any other value is | ||
# ignored. | ||
def initialize(*a, &b) | ||
@work = EM::Callback(*a, &b) | ||
@stops = [] | ||
@stopped = true | ||
end | ||
|
||
# Arguments: A callback (EM::Callback) to call once on the next stop (or | ||
# immediately if already stopped). | ||
def on_stop(*a, &b) | ||
if @stopped | ||
EM::Callback(*a, &b).call | ||
else | ||
@stops << EM::Callback(*a, &b) | ||
end | ||
end | ||
|
||
# Stop the tick loop immediately, and call it's on_stop callbacks. | ||
def stop | ||
@stopped = true | ||
until @stops.empty? | ||
@stops.shift.call | ||
end | ||
end | ||
|
||
# Query if the loop is stopped. | ||
def stopped? | ||
@stopped | ||
end | ||
|
||
# Start the tick loop, will raise argument error if the loop is already | ||
# running. | ||
def start | ||
raise ArgumentError, "double start" unless @stopped | ||
@stopped = false | ||
schedule | ||
end | ||
|
||
private | ||
def schedule | ||
EM.next_tick do | ||
next if @stopped | ||
if @work.call == :stop | ||
stop | ||
else | ||
schedule | ||
end | ||
end | ||
self | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
require "test/unit" | ||
require "eventmachine" | ||
|
||
class TestEmTickLoop < Test::Unit::TestCase | ||
def test_em_tick_loop | ||
i = 0 | ||
EM.tick_loop { i += 1; EM.stop if i == 10 } | ||
EM.run { EM.add_timer(1) { EM.stop } } | ||
assert_equal i, 10 | ||
end | ||
|
||
def test_tick_loop_on_stop | ||
t = nil | ||
tick_loop = EM.tick_loop { :stop } | ||
tick_loop.on_stop { t = true } | ||
EM.run { EM.next_tick { EM.stop } } | ||
assert t | ||
end | ||
|
||
def test_start_twice | ||
i = 0 | ||
s = 0 | ||
tick_loop = EM.tick_loop { i += 1; :stop } | ||
tick_loop.on_stop { s += 1; EM.stop } | ||
EM.run { EM.next_tick { EM.stop } } | ||
assert_equal 1, i | ||
assert_equal 1, s | ||
tick_loop.start | ||
EM.run { EM.next_tick { EM.stop } } | ||
assert_equal 2, i | ||
assert_equal 1, s # stop callbacks are only called once | ||
end | ||
|
||
def test_stop | ||
i, s = 0, 0 | ||
tick_loop = EM.tick_loop { i += 1 } | ||
tick_loop.on_stop { s += 1 } | ||
EM.run { EM.next_tick { tick_loop.stop; EM.next_tick { EM.stop } } } | ||
assert tick_loop.stopped? | ||
assert_equal 1, i | ||
assert_equal 1, s | ||
end | ||
|
||
def test_immediate_stops | ||
s = 0 | ||
tick_loop = EM::TickLoop.new { } | ||
tick_loop.on_stop { s += 1 } | ||
tick_loop.on_stop { s += 1 } | ||
assert_equal 2, s | ||
end | ||
|
||
def test_stopped | ||
tick_loop = EM::TickLoop.new { } | ||
assert tick_loop.stopped? | ||
tick_loop.start | ||
assert !tick_loop.stopped? | ||
end | ||
|
||
end |