报名参加CloudWeGo黑客松,奖金直推双丰收! 了解详情
写点什么

运用 Ruby 纤程进行异步 I/O:NeverBlock 和 Revactor

  • 2008-10-10
  • 本文字数:3944 字

    阅读完需:约 13 分钟

纤程(Fibers)慢慢地进入了Ruby 开发者们的视线中,将作为新的并发原语而广为使用。通过对纤程和非阻塞(或者说异步)I/O 这两种方法的组合,可以解决用户空间线程问题或者Ruby 1.9 的巨型解释器锁(Giant Interpreter Lock,简称GIL)的问题,这个问题使得Ruby 语言线程每次只能有一个是激活的。

最大的问题要数和使用那些阻塞的系统调用了,尤其是I/O 方面的。阻塞的系统调用,就拿读取来说,直到数据准备好的时候才会返回。在用户态的线程系统中,这意味着这个进程中的所有线程也都会阻塞。解决方法是将 I/O 系统与阻塞I/O 的方式进行解耦。有一种方法是在引发一个阻塞的系统调用以前捕捉它,以一种非阻塞的方式来处理这个I/O 请求,然后挂起这个纤程,给另外的纤程运行的机会。一旦系统收到这个I/O 请求的回应的话,纤程会再度被调度。

纤程提供了一个好用的并发工具来实现这个概念,而不会让使用者去忍受些什么不愉快。目前,两个程序库都着重于使用纤程实现解决方案。比较新的解决方案是 NeverBlock 程序库(Github 代码库包括 NeverBlock NeverBlock PG 支持ActiveRecord 的NeverBlock PG 适配器,以及支持异步操作的MySQLPlus MySQL 适配器)。更加通用的解决方案是建立在诸如Actor 和进程通信等Erlang 的思想之上的,来自Tone Arcieri 的Revactor 程序库。我们对来自NeverBlock 项目的 Mohammad A. Ali 来自Revactor 项目的Tone Arcieri 进行了访谈。

NeverBlock

InfoQ: 准确点儿说,NeverBlock 做了些什么?依我看,它提供了一个连接池把传入代码包装在纤程当中,等到连接可用的时候再恢复纤程。NeverBlock 的主要贡献是什么?

Mohammad A. Ali实现池机制对于 NeverBlock 其他部分的正常工作是必须的。最初的想法是,我们需要为应用程序提供即时的 IO 并发,例如 Rails、Merb 或者 Ramaze 等不支持完全线程安全的应用。

想要达到这个目标的话,我们需要一个 web 服务器来包装来自纤程的请求和 IO 程序库,纤程来自于 NeverBlock 的纤程池,而 IO 程序库(不仅仅是 DB 而是全部的 IO 操作)则是那些与纤程有关并利用其进行暂停和恢复请求的程序库。所有的一切都要使用一个诸如 EventMachine 或者 Rev 这样的事件循环来进行搭配。

InfoQ: NeverBlock::PG 是基于 NeverBlock 构建的,而且 PostgreSQL 驱动已经支持了非阻塞 I/O 且立等可用。如果这样的话,再引入 NeverblockPG 做什么呢?如果想添加另外一个事件驱动的话,比如说 Mysql,还没有非阻塞 I/O 的支持,那么 NeverBlock 会提供什么帮助呢?

Mohammad A. Ali NeverBlock::PG 驱动可以让非阻塞操作透明化,你只需要使从纤程池中 spawn 一个纤程出来即可。这样的话,你就可以这么写程序:

pool.spawn do<br></br> res1 = db.exec(query1)<br></br> res2 = db.exec(query2_that_depends_on_query1)<br></br>end一个普通的非阻塞实现会比这更加复杂。多亏了纤程,我们可以写出这种看似明明是阻塞的代码,却能够以非阻塞的行为运行。

对于 NeverBlock::PG 驱动,我们再更深入一点。我们刚刚发布了一个全新的 activerecord-neverblock-postgresql 适配器,将非阻塞 IO 带到了 ActiveRecord 中。我觉得很容易猜到 NeverBlock 的下一个目标是什么了。

最有意思的是,当你将 NeverBlock 应用于全栈应用的时候,它能以一种几乎透明的方式来实现。

NeverBlock 不能让一个阻塞的驱动变得非阻塞。它能让一个非阻塞的驱动的操作看起来更像是阻塞的方式,而不会牺牲非阻塞的特性。这既是说,我们未来的努力方向是类似于 Asymy 的(事件化 mysql 驱动)。

InfoQ: 你的程序库需要纤程(Fibers)的支持,而纤程只有 Ruby 1.9 才支持。你认为这对用户来说是一个问题吗(考虑到 Ruby 1.9 依然变化频繁而且并没有太多人去尝试)?你的程序库的特性会不会对用户去尝试 Ruby 1.9 起到一个刺激作作用呢?

Mohammad A. Ali 我相信纤程是 Ruby 1.9 中最棒的事情之一。同样的功能可以通过 Ruby 1.8 的 continuation 实现,但是性能上要差得多。另外稳定的 1.9 目前离发布也为期不远了,我觉得我们真的应该前行了。我相信 NeverBlock、Revactor 或者类似的东西提供的优点会帮助大家心甘情愿地转换过去的。

InfoQ: 看了看 NeverBlock 开放的源代码:你对 Fiber 使用了开放类并加入了一些方法。这么做的目的是什么?

Mohammad A. Ali 纤程对于存储纤程本地变量方面的功能是缺失的,然而线程可以做到。我需要这些功能来替代事务的当前 ActiveRecord 实现并使得纤程可查。我还需要它们来做到非阻塞操作的可选性,还有线程的上下文等等。

InfoQ: 你听说过 Revactor 吗?

Mohammad A. Ali 听过,我还搞过一点 Revactor。实际上我用 Rev 做为 NeverBlock 除了 EventMachine 以外的第二后端(仅仅是实验性质的)。但是 NeverBlock 和 Revactor 的目的不同。Revactor 为 Ruby 引入了一个新的并发模型,而 NeverBlock 目的是以最小的变化把并发引入当前的 Ruby 程序中。

编辑注:在本次采访完成之时,第一个异步MySQL 驱动的尝试──MySQLPlus 已经可用了。

Revactor

InfoQ: Revactor 的当前状态是什么?

Tony Arcieri: 在无数的项目当中有些被忽视,然而在很多商业应用上已经获得了成功。

InfoQ: Revactor 新版本的计划是什么?

Tony Arcieri: 最近 Aman Gupta 发布了一个“poor man’s Fibers”的 Ruby 1.8 的实现。这样的话将 Revactor 移植到 1.8 也是可以的了,然而性能上可能会很差。

目前,Revactor 还只是支持将全部的 Actors 放在同一个 Ruby 线程中。而更好的做法是可以在不同的线程中运行的 Actors 之间互相传递消息,但是目前还做不到。我已经和一些有兴趣实现它的人们聊过,希望很快就可以将这种方式引入 Revactor。

InfoQ: 用户需要直接对 Revactor 的 actors 进行编程吗?还是可以使用 RevActor 为其他的程序库实现后端,这样可以(对开发者)透明化?

Tony Arcieri: Revactor 和 Rubinius 中的 Actor 实现基本上兼容,但是目前 Rubinius 中的 Actors 还没有一个简单的方法可以像 Erlang 的 gen_tcp 那样进行网络编程。这也就是说,开发者们想使用 Actors 编写网络应用的话,可以先从 Revactor 开始,将来再移植到 Rubinius 上。

InfoQ: 你是如何调度阻塞 I/O 请求的?你使用内核线程来运行 I/O 请求吗?

Tony Arcieri: 当所有已发现的 Actor 消息都处理了、而且没有其他 Actors 是运行态的时候,Revactor 使用一个我编写的、叫做 Rev(和 EventMachine 类似)的事件程序库来监控 I/O 事件。Rev 使用 Ruby 1.9 中的 rb_thread_blocking_region() 函数来做到阻塞监控 I/O 读取的系统调用,因此不需要再使用独立的内核线程。 Revactor 动态地扩展了 Ruby 的 TCPSocket 类(Revactor::TCP),这样能做到看起来像阻塞的调用方式,但是实际上则是传回给 Actor 调度器。对现存的库进行 Moneky Patch(动态打补丁)来做到 Revactor::TCP 替换 Ruby Sockets 是很容易做到的。比如说,Revactor 就发布了一个小补丁,来实现在 Mongrel 中使用 Actors 而不是线程来并发。

InfoQ: 你如何处理 I/O 请求序列?是批量请求处理吗?

Tony Arcieri: 从表面上看,调用方式是“阻塞”的。当一个 I/O 请求处理结束后,当前的 Actor 就会休眠,并在下一次 I/O 竞争发生的时候被重新调度。这使得那些依赖于阻塞方式接口的程序库可以很方便的构建在 Revactor 之上。比如说 ActiveRecord 或者 DataMapper 之类的(目前还没有运行在 Revactor 之上)。

InfoQ: Rubinius 上 Actors 的状态是什么?

Tony Arcieri: 它做了所有 Revactor 能做的事,并且宣布将支持 TCP 套接字“active 模式”。这意味着在从 TCP 套接字中读取输入的时候,和以前不同的是,传入的数据是通过标准内部 Actor 消息异步送达到指定的 Actor 的。这使得 Actor 可以并行处理 I/O 和内部 Actor 消息。Rubinius 虚拟机目前正在使用 C++ 重写,在重写之后希望可以包含实现“active 模式”消息传递的全部特性。当它一旦可用的时候,我就会去尝试一下。

InfoQ: 有计划让 Revactor 支持 Rubinius 吗?

Tony Arcieri: 没有,Revactor 大量的利用到了 YARV 的特性。Rubinius 有一个很棒的并发模型和以 Task 和 Channel 的形式的 I/O 支持,而且 Rubinius 现有的 Actor 实现让这两者都非常的有效率。Revactor 和 Rubinius Actors 在 duck type 方面很大程度上是相似的,所以编写两者都兼容的程序并不是一件很头疼的事情。

InfoQ: 在 Rubinius 上运行 Actors 或者 Revactor 有什么优势呢(超过 Ruby 1.9)?

Tony Arcieri: 现在的话还是 Ruby 1.9 平台更好一些,对于现有的库有着更好的兼容性。Rubinius 正在开发当中,而且目前在重写。在将来,Rubinius 上会有很多优势能超越 Ruby 1.9,比如用于并发和 I/O 的 Task/Channel 抽象就会比 Ruby 1.9 中现存的更加清晰。在 1.8 和 1.9 上用于 I/O 的解决方案一直都是运行一个诸如 EventMachine 或者 Rev 的事件框架,与 Ruby 内建的 I/O 并行工作,而 Rubinius 在 I/O 方面一开始就已经占优势了。

InfoQ: 你知道使用 Revactor 的项目吗?

Tony Arcieri: 我已经听说了很多人在一些内部项目中使用它了,主要是用于并发 HTTP 客户端。我还不知道任何已经发布的项目用到了它。

InfoQ: 依赖 Ruby 1.9 的话,会不会对 Revactor 或者使用纤程的库的推广造成阻碍?

Tony Arcieri: 我当然可以想象的到这种情况。我也被 Ruby 1.9 的 bug 折磨过,所以能想象绝大部分的试用者都会小心翼翼的使用的。我已经了解到最近很多利用纤程来实现事件框架的项目冒了出来,比如 Ry Dahl 的 Flow web server。

查看英文原文: Using Ruby Fibers for Async I/O: NeverBlock and Revactor


志愿参与 InfoQ 中文站内容建设,请邮件至 editors@cn.infoq.com 。也欢迎大家到 InfoQ 中文站用户讨论组参与我们的线上讨论。

2008-10-10 00:113514
用户头像

发布了 80 篇内容, 共 21.0 次阅读, 收获喜欢 5 次。

关注

评论

发布
暂无评论
发现更多内容

Python图像处理丨带你认识图像量化处理及局部马赛克特效

华为云开发者联盟

人工智能 企业号九月金秋榜

云原生数据库极致弹性体验 - Amazon Aurora Serverless v2

亚马逊云科技 (Amazon Web Services)

数据库 云原生

软件测试中的『草莓酱定律』

BY林子

敏捷测试 草莓酱定律 温伯格

AI 时代的视频云转码移动端化——更快、更好、更低、更广

ZEGO即构

AI 音视频开发 视频云转码

干货|app自动化测试之Andriod WebView如何测试

霍格沃兹测试开发学社

干货|app自动化测试之Appium 源码分析

霍格沃兹测试开发学社

软件测试 | 测试开发 | 测试人生 | 拿到多个 offer 从了一线互联网公司并涨薪70%,90后小哥哥免费分享面试经验~

测吧(北京)科技有限公司

软件测试 测试 offer

软件测试 | 测试开发 | 测试人生 | 双非院校、入职某知名电商公司薪资翻倍还有股票奖励,这个90后小姐姐也太飒了吧?

测吧(北京)科技有限公司

测试 面试题 软件测试面试题

软件测试 | 测试开发 | 测试人生 | 三十而立终圆大厂梦,测试开发开启新征程

测吧(北京)科技有限公司

软件测试 测试 测试开发

软件测试 | 测试开发 | 测试人生 | 97年双非学历的小哥哥,2线城市涨薪100%,我酸了......

测吧(北京)科技有限公司

软件测试 测试

Meta公司内部项目-RaptorX:将Presto性能提升10倍

Alluxio

presto Alluxio #Facebook meta 9月月更

软件测试 | 测试开发 | 测试人生 | 年薪50w+ 并入职名企大厂,这是双非学历小哥哥给自己30岁的礼物

测吧(北京)科技有限公司

软件测试 测试

软件测试 | 测试开发 | 从跨专业手工测试转岗外包,再到 Python 测试开发,跳槽涨薪 85%!

测吧(北京)科技有限公司

软件测试 测试

瓴羊智能客服,基于钉钉重磅推出一体化的智能服务解决方案

瓴羊企业智能服务

软件测试 | 测试开发 | 多种框架小程序测试环境构建总结

测吧(北京)科技有限公司

软件测试 测试

IDaaS 系统ArkID一账通内置插件:图形验证码认证因素的配置流程

龙归科技

单点登录 Idaas

The main application of radio technology in aerospace field/IPQ4019 IPQ4029 ,802.11AC 2x2 2.4G&5G

wallys-wifi6

IPQ4019 ipq4029

干货|app自动化测试之Appium 源码修改定制分析

霍格沃兹测试开发学社

软件测试 | 测试开发 | 浅谈测试需求分析

测吧(北京)科技有限公司

测试 需求 用户需求分析

内存管理:程序是如何被优雅的装载到内存中

C++后台开发

内存管理 Linux内核 内核源码 内核开发 嵌入式开发

软件测试 | 测试开发 | Jenkins 持续集成体系介绍

测吧(北京)科技有限公司

软件测试 测试

NFT拍卖交易系统开发NFT商城

薇電13242772558

NFT

干货|app自动化之如何参数化用例

霍格沃兹测试开发学社

干货|app自动化测试之Appium 原理 与 JsonWP 协议分析

霍格沃兹测试开发学社

软件测试 | 测试开发 | 测试人生 | 从传统行业到名企大厂,薪资翻倍,我做到了

测吧(北京)科技有限公司

软件测试 测试

软件测试 | 测试开发 | 测试人生 | 双非院校跨城重新开始,薪资翻了2倍还多,这个90后小姐姐好飒

测吧(北京)科技有限公司

测试 测试工程师

软件测试 | 测试开发 | 测试人生 | 毕业2年,拒绝独角兽入职名企大厂涨薪10万+,这个95后小姐姐好飒

测吧(北京)科技有限公司

测试

软件测试 | 测试开发 | 测试人生 | 双非学历,从外包到某大厂只用了1年时间,在2线城市年薪近30万,我柠檬了......

测吧(北京)科技有限公司

软件测试 | 测试开发 | Jenkins job 机制该如何使用?

测吧(北京)科技有限公司

测试 测试工程师

软件测试 | 测试开发 | Hybird app开发入门之Native和H5页面交互原理

测吧(北京)科技有限公司

软件测试

软件测试 | 测试开发 | ADBLib 在 android 中的使用

测吧(北京)科技有限公司

android 测试

运用Ruby纤程进行异步I/O:NeverBlock和Revactor_Ruby_Werner Schuster_InfoQ精选文章