Chinaunix首页 | 论坛 | 博客
  • 博客访问: 392750
  • 博文数量: 69
  • 博客积分: 1984
  • 博客等级: 上尉
  • 技术积分: 953
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-28 00:43
个人简介

学无所长,一事无成

文章分类

全部博文(69)

文章存档

2015年(19)

2014年(14)

2013年(9)

2012年(17)

2010年(10)

我的朋友

分类: Python/Ruby

2013-11-26 14:11:50



同 Celluloid 类似,只需要在普通类中添加 include Celluloid 即可。下例展示一个 echo server:

  1. require 'celluloid/io'
  2. require 'celluloid/autostart'

  3. class EchoServer
  4.   include Celluloid::IO
  5.   finalizer :shutdown

  6.   def initialize(host, port)
  7.     puts "*** Starting echo server on #{host}:#{port}"

  8.     # Since we included Celluloid::IO, we're actually making a
  9.     # Celluloid::IO::TCPServer here
  10.     @server = TCPServer.new(host, port)
  11.     async.run
  12.   end

  13.   def shutdown
  14.     @server.close if @server
  15.   end

  16.   def run
  17.     loop { async.handle_connection @server.accept }
  18.   end

  19.   def handle_connection(socket)
  20.     _, port, host = socket.peeraddr
  21.     puts "*** Received connection from #{host}:#{port}"
  22.     loop { socket.write socket.readpartial(4096) }
  23.   rescue EOFError
  24.     puts "*** #{host}:#{port} disconnected"
  25.     socket.close
  26.   end
  27. 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。




阅读(1469) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~