Permalink
Browse files

Improvements in next_tick (shared uv_idle) thanks to Saul Ibarra (@sa…

  • Loading branch information...
1 parent 1c51380 commit c5be39b8dbfce0e08c308b98b97740db13b84ebb @ibc committed May 3, 2012
@@ -3,15 +3,14 @@
#include "ae_next_tick.h"
-// C variable indicating whether there are pending next_ticks.
-static int pending_next_ticks;
-
static ID id_method_execute_next_ticks;
void init_ae_next_tick()
{
- pending_next_ticks = 0;
+ ae_next_tick_uv_idle = ALLOC(uv_idle_t);
+ uv_idle_init(uv_default_loop(), ae_next_tick_uv_idle);
+ uv_unref(uv_default_loop());
rb_define_module_function(mAsyncEngine, "_c_next_tick", AsyncEngine_c_next_tick, 0);
@@ -31,21 +30,21 @@ static
void next_tick_callback(uv_idle_t* handle, int status)
{
AE_TRACE();
+
uv_idle_stop(handle);
- uv_close((uv_handle_t *)handle, ae_handle_close_callback_0);
- pending_next_ticks = 0;
+ uv_unref(uv_default_loop());
+
rb_thread_call_with_gvl(execute_next_tick_with_gvl, NULL);
}
VALUE AsyncEngine_c_next_tick(VALUE self)
{
AE_TRACE();
- if (pending_next_ticks == 0) {
- uv_idle_t* _uv_handle = ALLOC(uv_idle_t);
- uv_idle_init(uv_default_loop(), _uv_handle);
- pending_next_ticks = 1;
- uv_idle_start(_uv_handle, next_tick_callback);
+
+ if (! uv_is_active((uv_handle_t *)ae_next_tick_uv_idle)) {
+ uv_idle_start(ae_next_tick_uv_idle, next_tick_callback);
+ uv_ref(uv_default_loop());
}
return Qtrue;
}
@@ -5,26 +5,34 @@
#include "ae_udp.h"
+static uv_prepare_t *av_uv_prepare;
+
+
static
void prepare_callback(uv_prepare_t* handle, int status)
{
AE_TRACE();
// Check received interruptions in Ruby land.
rb_thread_call_with_gvl(rb_thread_check_ints, NULL);
-
- // If this uv_prepare is the only existing handle, then terminate the loop.
- if (uv_loop_refcount(uv_default_loop()) == 1)
- uv_close((uv_handle_t *)handle, ae_handle_close_callback_0);
}
static
VALUE run_uv_without_gvl(void* param)
{
AE_TRACE();
+ int ret;
+
+ ret = uv_run(uv_default_loop());
+
+ // Referece again av_uv_prepare and av_uv_idle_next_tick so they can be properly closed.
+ uv_ref(uv_default_loop());
+ uv_close((uv_handle_t *)av_uv_prepare, ae_handle_close_callback_0);
+ //uv_ref(uv_default_loop());
+ //uv_close((uv_handle_t *)ae_next_tick_uv_idle, ae_handle_close_callback_0);
- if (! uv_run(uv_default_loop())) {
+ if (! ret) {
return Qtrue;
}
else
@@ -35,18 +43,19 @@ VALUE run_uv_without_gvl(void* param)
VALUE AsyncEngine_c_run(VALUE self)
{
AE_TRACE();
- uv_prepare_t *_uv_prepare = ALLOC(uv_prepare_t);
+ av_uv_prepare = ALLOC(uv_prepare_t);
- uv_prepare_init(uv_default_loop(), _uv_prepare);
- uv_prepare_start(_uv_prepare, prepare_callback);
+ uv_prepare_init(uv_default_loop(), av_uv_prepare);
+ uv_prepare_start(av_uv_prepare, prepare_callback);
+ uv_unref(uv_default_loop());
return rb_thread_call_without_gvl(run_uv_without_gvl, NULL, RUBY_UBF_IO, NULL);
}
/*
* Returns the number of handlers in the loop.
- * NOTE: The returned number is the real number of handles minus 1 (the prepare handle).
+ * NOTE: The returned number is the real number of handles minus 1 (the av_uv_prepare handle).
*/
VALUE AsyncEngine_num_handles(VALUE self)
{
@@ -18,5 +18,8 @@
VALUE mAsyncEngine;
+// A permanent uv idle for next_tick.
+uv_idle_t* ae_next_tick_uv_idle;
+
#endif /* #ifndef ASYNCENGINE_RUBY_H */
@@ -1,5 +1,7 @@
#!/bin/bash
+set -e
+
LIBUV_GIT_REPO="https://github.com/joyent/libuv.git"
LIBUV_GIT_BRANCH="master"
LIBUV_GIT_REVISION="9984d15"
View
@@ -0,0 +1,69 @@
+$LOAD_PATH.insert 0, File.expand_path(File.join(File.dirname(__FILE__), "../", "lib"))
+
+require "asyncengine"
+require "eventmachine-le"
+require "benchmark"
+
+
+TIMES = 3000
+
+
+puts "PID = #{$$}"
+sleep 0.5
+puts
+
+puts
+printf "1) AE::PeriodicTimer: "
+puts Benchmark.realtime {
+ $i = 0
+ AE.run do
+ t = AE::PeriodicTimer.new(0.001) do
+ #printf(".")
+ $i += 1
+ t.cancel if $i == TIMES
+ end
+ end
+}
+
+puts
+printf "2) EM::PeriodicTimer: "
+puts Benchmark.realtime {
+ $i = 0
+ EM.run do
+ t = EM::PeriodicTimer.new(0.001) do
+ #printf(".")
+ $i += 1
+ EM.stop if $i == TIMES
+ end
+ end
+}
+
+puts
+printf "3) AE::next_tick: "
+puts Benchmark.realtime {
+ $i = 0
+ AE.run do
+ (TIMES*100).times do
+ AE.next_tick do
+ #printf(".")
+ $i+=1
+ printf() if $i == TIMES
+ end
+ end
+ end
+}
+
+puts
+printf "4) EM::next_tick: "
+puts Benchmark.realtime {
+ $i = 0
+ EM.run do
+ (TIMES*100).times do
+ EM.next_tick do
+ #printf(".")
+ $i += 1
+ EM.stop if $i == TIMES
+ end
+ end
+ end
+}
View
@@ -0,0 +1,42 @@
+#!/usr/bin/env ruby
+
+require "eventmachine"
+$LOAD_PATH.insert 0, File.expand_path(File.join(File.dirname(__FILE__), "../", "lib"))
+require "asyncengine"
+
+
+Thread.abort_on_exception = true
+
+
+$ae_timer_ticks = 0
+$em_timer_ticks = 0
+$time_start = Time.now
+
+at_exit do
+ puts "\n\nINFO: exiting...\n- interval = #{Time.now - $time_start} seconds\n- em_timer_ticks = #{$em_timer_ticks}\n- ae_timer_ticks = #{$ae_timer_ticks}\n\n"
+
+ exit!
+end
+
+def add_em_tick
+ printf "E"
+ $em_timer_ticks+=1
+ EM.next_tick { add_em_tick }
+end
+
+def add_ae_tick
+ printf "A"
+ $ae_timer_ticks+=1
+ AE.next_tick { add_ae_tick }
+end
+
+
+
+# EventMachine with next_tick.
+t1 = Thread.new { EM.run { EM.next_tick { add_em_tick } } }
+
+# AsyncEngine with next_tick.
+t2 = Thread.new { AE.run { AE.next_tick { add_ae_tick } } }
+
+t1.join rescue nil
+t2.join rescue nil
View
@@ -10,7 +10,21 @@
-#loop do AE.run { AE.ip4("1.2.003.4.3.4.5", 9999999) } end ; exit
+#AE.run { } ; puts "YA" ; exit
+
+#loop do AE.run { AE.add_timer(0) { puts "YA" } } end
+
+
+
+if true and false
+ AE.run do
+ AE.test_send_udp4("1.2.3.4", 9999, "111")
+ AE.test_send_udp4("1.2.3.4", 9999, "222")
+ AE.test_send_udp4("1.2.3.4", 9999, "333")
+ AE.add_periodic_timer(1) { printf "." }
+ end
+ exit
+end
@@ -20,20 +34,20 @@
if true and false
- Thread.new { loop { puts "---t1---" ; sleep 0.001 } }
- Thread.new { loop { puts "---t2---" ; sleep 0.001 } }
- AE.add_periodic_timer(0.001) { puts "***AE timer 1***" }
- AE.add_periodic_timer(0.001) { puts "***AE timer 2***" }
+ Thread.new { loop { puts " -t1-" ; sleep 0.001 } }
+ Thread.new { loop { puts " -t2-" ; sleep 0.001 } }
+ AE.add_periodic_timer(0.001) { puts " - ***AE timer 1***" }
+ AE.add_periodic_timer(0.001) { puts " - ***AE timer 2***" }
end
if true and false
- t1 = AE::PeriodicTimer.new(1,0) { puts "--- t1 periodic timer should be stopped after some seconds !!! ---" }
+ t1 = AE::PeriodicTimer.new(1,0) { puts " - t1 periodic timer should be stopped after some seconds !!! ---" }
puts t1.inspect
AE.add_timer(4) do
- t2 = AE::Timer.new(2) { puts "--- t2 single timer should NOT be stopped !!! ---" }
+ t2 = AE::Timer.new(2) { puts " - t2 single timer should NOT be stopped !!! ---" }
puts t2.inspect
- puts "--- canceling t1 ---"
+ puts " - canceling t1 ---"
t1.cancel
AE.add_timer(1) { puts "exiting..." ; exit }
end
@@ -70,10 +84,10 @@ def initialize a,b
$interval = 0.1
pt1 = AE::PeriodicTimer.new($interval) do
if $interval > 1
- puts "--- pt1: interval > 1, stopping timer"
+ puts " - pt1: interval > 1, stopping timer"
pt1.stop
else
- puts "--- pt1: interval=#{$interval} , setting next interval in #{$interval * 2}"
+ puts " - pt1: interval=#{$interval} , setting next interval in #{$interval * 2}"
pt1.interval = ($interval *= 2)
end
end
@@ -83,13 +97,13 @@ def initialize a,b
if true #and false
tt = AE::PeriodicTimer.new(0.1) { puts "LALALA" }
AE.add_timer(0.2) do
- puts "--- cancel 1 returns #{tt.cancel}"
- puts "--- cancel 2 returns #{tt.cancel}"
- puts "--- set_interval 1 returns #{tt.set_interval 1.1}"
+ puts " - cancel 1 returns #{tt.cancel}"
+ puts " - cancel 2 returns #{tt.cancel}"
+ puts " - set_interval 1 returns #{tt.set_interval 1.1}"
AE.add_timer(0.3) do
- puts "--- cancel 3 returns #{tt.cancel}"
- puts "--- cancel 4 returns #{tt.cancel}"
- puts "--- set_interval 2 returns #{tt.set_interval 2.2}"
+ puts " - cancel 3 returns #{tt.cancel}"
+ puts " - cancel 4 returns #{tt.cancel}"
+ puts " - set_interval 2 returns #{tt.set_interval 2.2}"
end
end
end
@@ -122,7 +136,7 @@ def initialize a,b
10.times { AE.next_tick { puts i+=1 } }
AE.next_tick { puts "A" }
AE.next_tick { puts "B" ; AE.next_tick { puts "E" } ; puts "C" }
- AE.next_tick { puts "D" }
+ AE.next_tick { puts "D" ; AE.next_tick { puts "F" ; AE.next_tick { puts "G" } } }
end
end

0 comments on commit c5be39b

Please sign in to comment.