eventmachine 是一个轻量级的事件驱动 I/O 模型框架,是 ractor 模型的。
下面一步步来介绍一下 eventmachine.(eventmachine 可以简写成 em)
$ vim test1.rb
#test1.rb
require 'rubygems'
require 'eventmachine'
EM.run {
EM.add_periodic_timer(1) {
puts "hello world"
}
}
这个程序每隔一秒输出 hello world.
它是如何工作的呢?require 之后,调用了 EM.run, 它接收一个代码块做为参数。
(TODO 具体它是怎么工作的不太清楚,应该是一个事件循环,执行EM.run {puts "i am in run"}
会有一个输出后然后阻塞住.....)
add_periodic_timer 是周期定时器,上例表示每隔一秒执行一次代码块参数。这个代码块称之为回调。
可以使用 EM.stop 来结束事件循环
require 'rubygems'
require 'eventmachine'
EM.run {
count = 1;
EM.add_periodic_timer(1) {
EM.stop if count == 5
puts "#{count}: hello world"
count += 1
}
}
以上代码打印 5 次 hello world 后结束。
高效的 IO 是 eventmachine 的全部意义所在,在你使用 eventmachine 进行网络 IO 编程时,要么直接使用 evnetmachine,
要么使用 eventmachine 扩展的某个 lib,一般以 em-开头,eventmachine 自带了两个不同的 HTTP client,但都有些问题,
这里推荐一个强大的模块:em-http-request
为什么要使用 em 来进行 IO 呢,如果你是使用标准库中的 Net::HTTP,向一个 URI 请求,预计要 10s 的响应时间,那么你的进程就会阻塞 10s,在此期间,上面的定时器都不会触发,一直到返回结束或超时。
$vim test2.rb
#test2.rb
require 'rubygems'
require 'eventmachine'
require 'em-http'
EM.run {
http = EM::HttpRequest.new("http://www.goole.com").get
http.callback { |h|
puts h.response_header
EM.stop
}
}
EM::HttpRequest
句 get 一个 url,callback 接收一个代码块参数,获得数据后执行。
连接的形式如 EM::HttpRequest.new(url,connect_options).methods request_options
具体可见em-http-request的文档
在设计 API 接口时,需要有办法来区分响应成功或者失败。在 ruby 中,有两种常用的方法,一种是返回 nil,一种是抛出异常.
EM 提供了一种更为优雅的方案:the deferrable.
deferable 是一个对象,通过它你可以添加上成功或者失败后的回调方法,分别为 callback 和 errback.有兴趣可以看源码.
前面代码中调用 HttpRequest#get 时,返回的就是一个 deferrable.(实际上返回的是一个 EM::HttpClient 实例对象,它被 mixin 到了 EM::Deferrable 模块中.),当然也有更为通用的方法,就是直接使用 EM::DefaultDeferrable.
当我需要写一个新的 API 时,一般会使用 HTTParty,因为它很容易使用。