Ruby 3发布,为何性能能提升3倍

开发 后端
对于所有Rubyists来说,2020年是特殊的一年。难道不是这样么?Ruby 2于2013年发布,我们使用Ruby 2.x已有7年之久,我们一直在等待Ruby 3的发布。

对于所有Rubyists来说,2020年是特殊的一年。难道不是这样么?Ruby 2于2013年发布,我们使用Ruby 2.x已有7年之久,我们一直在等待Ruby 3的发布。

终于,等待结束了。我们终于在圣诞期间迎来了Ruby 3.0.0,它为这种高级通用编程语言提供了更高的性能和其他功能,这不啻给我们最好的圣诞节礼物。现在是时候拆开礼品盒了,看看我们得到的所有Ruby 3功能。

 

Ruby 3发布,为何性能能提升3倍

Ruby 3.0的开发着眼于更高的性能、并发性和类型,并成功实现了比Ruby 2.0的性能快3.0倍的目标。3.0倍速是在使用新的Ruby 3.0的Just-In-Time(JIT)运行时编译器时实现的,但与Ruby 2相比,就其VM实现而言,仍然是相当可观的提速。

也许有人会问,为什么把Ruby 3.0的性能提速跟Ruby 2.0对比,而不是诸如Ruby 2.7?请去官网阅读发行说明,将性能提高3倍是2015年的既定目标。

Ruby3.0的JIT表现出非常出色的性能,非常适合需要多次调用几种方法的工作负载。Ruby 3.1有望为需要更多调用方法的工作负载提高JIT性能。

Ruby 3.0还为并行执行功能提供了实验性的"Ractor",而无需考虑线程安全性;Fiber Scheduler允许拦截阻塞操作、改进静态分析、改进的单行模式匹配以及许多其他更改。

Ruby 3主要更新

数字3在Ruby 3版本中非常有意义。它是发布版本号,使性能提高了3倍,核心贡献者(Matz,TenderLove和Koichi)也是三人组。同样,Ruby 3有3个主要目标:更快、并发性更好并确保正确性。

 

Ruby 3发布,为何性能能提升3倍

1. Ruby 3性能

性能是Ruby 3的主要关注重点之一。实际上,围绕Ruby 3,开发者团队内部最初就进行了讨论。Ruby创始人Matz(松本行弘)于2015年设定了一个雄心勃勃的目标,就是将Ruby的速度提高3倍。

什么是Ruby 3x3?

在讨论这一点之前,让我们重新审视Ruby的核心理念。

Matz说到:"我希望看到Ruby帮助世界上的每个程序员提高生产力,享受编程并感到幸福。"

关于Ruby 3x3,有人问是否目标是使Ruby成为最快的语言?答案是不。Ruby 3x3的主要目标是使Ruby的速度比Ruby 2快3倍。

Matz谈到:"没有一种语言足够快。"

Ruby并非为追求速度最快而设计,如果这是目标,那么Ruby将不会是今天这种局面。随着Ruby语言性能的提高,它无疑有助于我们的应用程序更快且可扩展。

Matz坦承:"在Ruby语言的设计中,我们主要集中在生产力和编程乐趣上。结果,Ruby太慢了。"

可以衡量性能的区域有两个:内存和CPU。

CPU优化

Ruby中已进行了一些增强,以提高速度。Ruby团队从以前的版本中优化了JIT(Just In Time)编译器。Ruby MJIT编译器最早是在Ruby 2.6中引入的。Ruby 3 MJIT具有更好的安全性,并且似乎在很大程度上提高了Web应用程序的性能。

MJIT的实现不同于通常的JIT。当方法被反复调用(例如10000次)时,MJIT将选择可以编译为本机代码的方法并将其放入队列。稍后MJIT将获取队列并将其转换为本地代码。

内存优化

Ruby 3带有增强的垃圾收集器。它具有类似python的缓冲区的API,有助于更好地利用内存。从Ruby 1.8开始,Ruby在垃圾回收算法方面不断进步。

 

[[360513]]

自动垃圾压缩

垃圾收集的最新变化是垃圾压缩。它是在Ruby 2.7中引入的,该过程有点手动。但是在版本3中,它是全自动的,适当调用压缩程序以确保适当的内存利用率。

对象分组

垃圾压缩器移动堆中的对象。它将分散的对象组合在一起放在内存中的某个位置,以便后面更大的对象可以有效利用内存。

2. Ruby 3中的并行性和并发性

并发是任何编程语言的重要关注点之一。Matz认为Ruby程序员未能正确地使用线程这一抽象层。

Matz表示:"我很遗憾添加线程。"

Ruby 3使应用程序并发运行变得容易得多。Ruby 3中增加了一些与并发相关的功能和改进。

Fibers

在Ruby 3中,Fibers的引进被认为是突破性的。Fibers是轻量级工作线程,看起来像线程,但具有一些优势。它比线程消耗更少的内存。它为程序员提供了更大的控制权,使其可以定义可以暂停或恢复的代码段,从而实现更好的I/O处理。

Fiber Scheduler

Fiber Scheduler是Ruby 3中添加的一项实验性功能。它被引入来拦截诸如I/O之类的阻塞操作。可喜的是,它允许轻量级并发,并且可以轻松集成到现有代码库中,而无需更改原始代码逻辑。这是一个接口,可以通过诸如EventMachine或Async之类的gem创建包装器来引入,此接口设计允许事件循环实现与应用程序代码之间的关注点分离。

以下是HTTP使用并发发送多个请求的示例Async。

 

  1. require 'async'  
  2. require 'net/http'  
  3. require 'uri'  
  4. LINKS = [  
  5. 'https://xmyy.com' 
  6. 'https://www.xmyy.com'  
  7.  
  8. Async do  
  9. LINKS.each do |link|  
  10. Async do  
  11. Net::HTTP.get(URI(link))  
  12. end  
  13. end  
  14. end 

Ractors(Guilds)

众所周知,Ruby的globalVM lock(GVL)阻止大多数Ruby线程并行计算。Ractor可以解决此问题,GVL可以提供更好的并行性。Ractor是类似于Actor-Model的并发抽象,旨在提供并行执行而无需担心线程安全。

Ractors允许不同Ractor中的线程同时计算。每个Ractor具有至少一个线程,该线程可以包含多个Fibers。在Ractor中,在给定的时间只允许执行一个线程。

以下程序返回一个非常大的平方根。它并行计算两个数字的结果。

 

  1. # Math.sqrt(number) in ractor1, ractor2 run in parallel  
  2. ractor1, ractor2 = *(1..2).map do  
  3. Ractor.new do  
  4. number = Ractor.recv  
  5. Math.sqrt(number)  
  6. end  
  7. end  
  8.  
  9. # send parameters  
  10. ractor1.send 3**71  
  11. ractor2.send 4**51  
  12.  
  13. p ractor1.take #=> 8.665717809264115e+16  
  14. p ractor2.take #=> 2.251799813685248e+15 

3.静态分析

我们需要测试以确保我们程序的正确性。但是,从本质上讲,测试可能意味着重复的代码工作。

Matz甚至吐槽:"我讨厌测试,因为它不是人干的。"

为了确保程序的正确性,除了测试之外,静态分析是个不错的工具。

静态分析依赖于内联类型注释。解决此难题的解决方案是使.rbs文件与我们的.rb文件平行。

RBS

RBS是一种描述Ruby程序结构的语言。它为我们提供了该程序的概述,以及如何定义整体类,方法等。使用RBS,我们可以编写Ruby类、模块、方法、实例变量、变量类型和继承的定义。它支持Ruby代码中的常用模式以及高级类型(如并集和鸭子duck typing类型)。

这些.rbs文件类似于.d.tsTypeScript中的文件。以下是一个.rbs文件外观的小例子。具有类型定义的优点是可以针对实现和执行进行验证。

下面的示例是不言自明的。我们需要在这里注意的一件事是each_post接受一个块或返回一个枚举器。

 

  1. user.rbs  
  2. class User  
  3. attr_reader name: String  
  4. attr_reader email: String  
  5. attr_reader age: Integer  
  6. attr_reader posts: Array[Post]  
  7. def initialize: (name: String,  
  8. email: String,  
  9. age: Integer) -> void  
  10. def each_post: () { (Post) -> void } -> void  
  11. | () -> Enumerator[Post, void]  
  12. end 

其他值得注意的变化

  • 粘贴到IRB中的速度要快得多。
  • 回溯的顺序已颠倒。首先打印错误消息和行号,然后打印其余的跟踪信息。
  • Hash#transform_keys 接受将旧密钥与新密钥映射的哈希。
  • 插值字符串文字在# frozen-string-literal: true使用时不再冻结。
  • Symbol#to_proc现在返回一个lambda Proc。
  • 添加了Symbol#name ,它以冻结的字符串形式返回符号的名称。

过渡

为了满足Ruby 3的目标需求,许多核心库已经作了修改。但这并不意味着我们的旧应用程序会突然停止工作。Ruby团队已确保这些更改向后兼容。我们可能会在现有代码中看到一些弃用警告。开发人员可以修复这些警告,以从旧版本平稳过渡到新版本。我们都准备使用新功能并希冀从新的性能改进中受益。

结论

随着性能、内存利用率、静态分析以及Ractors和Scheduler等新功能的极大改进,我们对Ruby的未来充满信心。使用Ruby 3,应用程序可以具有更大的可伸缩性和更令人愉快的使用。即将到来的2021年不仅是所有Rubyists的新年,而且是一个新时代。

责任编辑:未丽燕 来源: 今日头条
相关推荐

2019-06-25 10:11:01

cpu计算机测评

2012-02-16 09:15:48

JavaJActor

2012-05-07 23:19:00

RhinoJavaJVM编程语言

2012-03-15 09:21:25

ExpresionJJava

2010-06-08 08:53:16

opensuse 11

2009-06-23 21:03:55

Linux

2009-06-19 10:45:05

NetBeans 6.

2010-04-26 09:06:03

JavaFX 1.3

2013-02-26 09:36:57

RubyRuby 2.0

2011-01-06 09:57:31

Linux Kerne

2012-03-30 14:31:53

HibernateJava

2011-03-03 09:42:05

Ubuntu 11.0

2012-02-29 10:54:21

JavaPlay Framew

2015-11-16 11:31:35

Kubernetes网络性能新版本特性

2009-07-21 12:49:10

Ruby on RaiRoR

2011-07-07 10:33:27

Ruby

2011-10-10 09:56:43

Ruby

2011-12-21 11:13:22

JavaScript

2012-05-23 10:22:36

JBossJava

2011-03-07 09:22:51

点赞
收藏

51CTO技术栈公众号