在Ruby中执行非阻塞I/O的首选方法是什么?

9

如果我想要获取一个网页进行解析,但不想在I/O操作期间阻塞CPU。是否有类似于Python的Eventlet库的东西?

2个回答

18

最好的Ruby HTTP客户端库是Typhoeus,可以用于以非阻塞的方式并行执行多个HTTP请求。它具有阻塞和非阻塞接口:

# blocking
response = Typhoeus::Request.get("http://stackoverflow.com/")
puts response.body

# non-blocking
request1 = Typhoeus::Request.new("http://stackoverflow.com/")
request1.on_complete do |response|
  puts response.body
end
request2 = Typhoeus::Request.new("http://stackoverflow.com/questions")
request2.on_complete do |response|
  puts response.body
end
hydra = Typhoeus::Hydra.new
hydra.queue(request1)
hydra.queue(request2)
hydra.run # this call is blocking, though

另一个选择是em-http-request,它运行在EventMachine之上。它具有完全非阻塞的接口:

EventMachine.run do
  request = EventMachine::HttpRequest.new('http://stackoverflow.com/').get
  request.callback do
    puts request.response
    EventMachine.stop
  end
end

em-http-request还提供了一个接口,可以并行发送多个请求,类似于Typhoeus Hydra。

em-http-request的缺点是它与EventMachine绑定。EventMachine本身是一个很棒的框架,但它是一个全盘承包的方案。你需要以事件/传递方式编写整个应用程序,这已经被证明会导致脑损伤。Typhoeus更适合不需要事件的应用程序。


1
当你说hydra.run的调用是阻塞的时候,只要它保持在睡眠状态,并在I/O完成时被唤醒,那就没问题了。这就是我想要实现的,就像Windows中的事件驱动I/O一样。无论在哪个线程上进行hydra.run调用时,在其阻塞期间都不应该占用CPU资源,因为本质上它正在等待一个事件。这就是hydra的工作方式吗?如果不是,我认为它有点失去了意义。如果您能确认一下,我会将其标记为已接受。谢谢。 - Fast Fish
在我的情况下,我需要释放当前线程并且不阻塞任何操作。有没有办法避免阻塞的 'hydra.run' 调用?还有其他支持完全非阻塞方法的 HTTP Ruby 宝石吗? - Jeremy Haile
我认为你可以使用Celluloid::IO来完成,例如:https://github.com/httprb/http.rb/wiki/Parallel-requests-with-Celluloid%3A%3AIO - Theo
Celluloid被Suckerpunch gem很好地封装,它让你可以启动后台运行的worker任务(如果需要,可以进行外部调用)。事实上,看起来Suckerpunch在去年底改用了Concurrent Ruby而不是Celluloid。如果进程被终止,你将失去这些workers,你可能需要做出相应的处理。 - A Fader Darkly
或者你可以直接使用 Concurrent Ruby。 - A Fader Darkly

5

我不确定Eventlet是做什么的,但Ruby有EventMachine,这是一个用于非阻塞IO(等等)的库。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接