Ruby ractor 应用到真实项目,结果彻底失望

tomanderson · 2021年02月07日 · 最后由 aaline57963 回复于 2021年02月18日 · 1171 次阅读

我的一个项目中大量使用了 gem parallel 开多进程,因此对 ractor 很期待,希望能达到 cpu 性能接近多线程、内存占用小的效果。现在已经折腾了一个礼拜,实际结果非常失望。

首先,ractor 的用法让我觉得很别扭。比如,我要运行 A.xxx 方法,而它又调用了 B.yyy 方法,需要 Ractor.new(A,B) 把所有 class 全部传入才能使用,否则报错方法 undefined。而且,module 中的方法不能直接使用,也不能和 class 一样传入,我只能在 initializer 中 include module 使其能够在 ractor 中访问。

当然,只要效果能管用,这些都在其次,无非是多了点填坑时间。然而,当我最终在真实项目中把 ractor 跑起来之后,简直大跌眼镜:

ractor 开 2 线程,竟然比开 1 线程慢近 1 倍。

这里说的开 1 线程,还不是不用 ractor,只是调整 ractor 并发数而已,连代码都不变。看 cpu 占用发现,2 线程确实能跑满 2 个核心,但就是比 1 线程慢。

我的第一反应自然是:代码有问题吧?会不会 2 线程执行的总工作量比 1 线程多?于是我把 ractor 线程执行的方法改成一个计算斐波那契数列的简单函数,它的运行时间是固定的。再测,发现效果正常了:2 线程用时是 1 线程的一半左右,继续增加线程超过 cpu 核心数后,耗时不变。又改为 parallel 跑,2 线程也比 1 线程快 30% 左右,不可能出现线程数增加速度反而变慢的效果。

那么这个让 ractor 多线程变慢的方法有何神奇之处?我觉得只是数学计算和创建对象比较多而已。如果连这都没有,那也用不着跑多线程了。

ractor 目前是 experimental 状态,我也不指望现在就大面积应用到真实项目。然而在我的项目中,我竟然找不到一处可以换成 ractor 的地方:除了上述无法理解的变慢问题,还发现 1 个 gem 导致 rails 崩溃、1 个 gem 不兼容无法调用。

但愿是我自己使用的问题,而不是 ractor 本身有问题。如果 ractor 真的不成器的话,对 ruby 实在不是一个好消息,因为 ruby 也没有另一个真正意义上的多线程了。

https://ruby-china.org/topics/40583

但是,历史遗留问题依然需要解决。随着 Fiber Scheduler 在 Ruby 3 引用来提高 I/O 密集场景下单一线程利用率极低的问题;我们需要进一步解决,计算密集场景下,多线程的利用率。 为了解决这一问题,Ruby 3 引入了 Ractor 模型。

先看你要解决的是什么问题,rails 项目可不是计算密集场景

就算 ractor,fiber 成熟了,对 rails 使用者也应该是无感知的,业务代码都会跑在单个 ractor/fiber 里,是框架跟 webserver 决定的,就像现在 puma rails 都用多线程编程,但是作为 rails 使用者几乎不需要写多线程代码,如果对多线程理解不好,多线程代码反而会拖慢项目速度,比如你多线程查数据库,别的请求就拿不到数据库连接。

tomanderson ractor 跑一段简单代码,百分百崩溃 提及了此话题。 02月08日 11:10
piecehealth 回复

我目前对 ractor 的期望不是它快还是慢,适合什么场景,而是能正常运行就好。我测了一段简单代码,ractor 运行 100% 崩溃,请看下:https://ruby-china.org/topics/40902。 任何技术都有优缺点,但底线是能运行,如果同样的代码用 ractor 就报错崩溃,那这个不是场景的问题,就是 ractor 本身的问题。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号