同 Celluloid 类似,只需要在普通类中添加 include Celluloid 即可。下例展示一个 echo server:
-
require 'celluloid/io'
-
require 'celluloid/autostart'
-
-
class EchoServer
-
include Celluloid::IO
-
finalizer :shutdown
-
-
def initialize(host, port)
-
puts "*** Starting echo server on #{host}:#{port}"
-
-
# Since we included Celluloid::IO, we're actually making a
-
# Celluloid::IO::TCPServer here
-
@server = TCPServer.new(host, port)
-
async.run
-
end
-
-
def shutdown
-
@server.close if @server
-
end
-
-
def run
-
loop { async.handle_connection @server.accept }
-
end
-
-
def handle_connection(socket)
-
_, port, host = socket.peeraddr
-
puts "*** Received connection from #{host}:#{port}"
-
loop { socket.write socket.readpartial(4096) }
-
rescue EOFError
-
puts "*** #{host}:#{port} disconnected"
-
socket.close
-
end
-
end
这段代码非常简单,同普通的 TCPServer 代码没有太大区别。通过 include Celluloid::IO 我们获得了并发处理能力,学习了 Celluloid 基础知识后,这些都很好理解。
同传统的 TCPServer 代码相比,主要的变化如下:
1、通过 include Celluloid::IO 将传统的 TCPServer 和 TCPSocket 类替换成基于 Celluloid::IO 的事件驱动模式。
2、异步方法调用:见代码中 async.run 和 async.handle_connection 调用。通过这种方式,方法调用作为消息被放入队列,直到当前方法处理完毕后才唤醒执行。你可以往队列中随便放入多少方法调用,这就类似于 Twisted或者 EventMachine 或Node 中的 "call later" 或 "next tick"。echo server 会将接收请求的程序置于后台,对每一个接入的连接也会置于后台运行。
3、Reactor + Fibers: Celluloid::IO 混合使用了 Actor 和 Reactor 原则。Celluloid::IO actors 的 mailboxes 使用的是 的阻塞机制。当当前任务需要一个阻塞 I/O 调用时,它首先发出一个非阻塞请求,如果 socket 未就绪则任务挂起,直到 reactor 检查到操作准备就绪,就恢复挂起任务。
FAQ:
问题:我一定要全部使用 Celluloid::IO 吗?我能不能使用包含普通阻塞IO 的 Ruby库呢?
当然不是,你可以使用阻塞IO 的 Ruby 库。但有些情况使用 Celluloid::IO 你会感觉特别爽。Celluloid::IO 允许你通过 Celluloid 的 actor 消息机制进行并发 IO 操作,这非常强大。了解更多信息,参考:
何时该使用 Celluloid::IO
同 Node.js 等系统不同,Celluloid 中并非随时都需要这种事件驱动型的 I/O。一般基于以下理由我们会使用 Celluloid::IO:
1、在进行阻塞I/O操作时,Celluloid actors 将无法响应 mailboxes 中收到的新的消息。只有阻塞I/O处理完毕后,才会继续处理消息,阻塞I/O执行期间,整个 actor 都会被阻塞住。如果你既希望能进行消息的并发处理,又希望能进行 I/O操作的并发处理,那你就应该使用 Celluloid::IO。特别是针对无限循环,永不中断的阻塞操作,比如监听一个 TCP 连接。
2、Celluloid 会为每个 actor 分配一个 native thread。在Ruby中 native thread 的内存开销并不大 (20KB左右),使用 Celluloid::IO 这个开销甚至更低。如果你处理10000个以上的连接,每个连接分配一个 actor ,那么可以考虑使用 Celluloid::IO。
3、Celluloid::IO 的目标是全集成进 Celluloid以及 DCell 系统中。DCell 有望彻底支持串行化I/O处理,这意味着你可以在各个节点间灵活地无缝切换。
综上所述,当你开始接触学习 Celluloi,你可以从阻塞 I/O 开始起步,直到你弄明白 Celluloid 的基础原理,进一步遇到以上问题就可以迁移到 Celluloid::IO。
阅读(1516) | 评论(0) | 转发(0) |