Ruby Ractor和解释语言中的并行性

Ruby Ractor和解释语言中的并行性 Ractor Ruby 3.0 的主要特性之一是引入了“ractor”。 Ractor 是 Ruby 的一个新的并发抽象。 与 Ruby 线程不同,ractor 可以并行运行。 由于 Ruby 全局虚拟机锁(GVL),即使每个 Ruby 线程都映射到本地线程,也只能有一个活动线程在运行。 但是引入 ractor 后,可以有多个 GVL,每个 ractor 有一个。 这就是 ractor 可以并行执行的原因。 ractor 的引入使 Ruby 能够实现真正的并行性,同时使用一个解释器。 在我们深入研究 ractor 实现之前,我想首先谈谈为什么 Ruby 有 GVL。 Global VM Lock Python 中的 GVL 或 GIL(全局解释器锁)。它是一种解释器范围的锁,可确保在任何给定时间只有一个线程正在执行。它的存在是为了方便解释器的开发。要理解为什么只有解释型语言有这个而其他语言没有,我们需要知道解释器是做什么的。 Ruby 允许动态添加类/模块的实例/类变量,它将这些信息存储在一个表中。现在,如果两个线程正在修改这个表,就会发生数据竞争。解释器所做的另一件事是垃圾收集。关于垃圾收集的信息存储在“对象空间”中,垃圾收集器将遍历这个空间,删除每个未被引用的对象。现在,如果一个线程触发垃圾收集器但另一个线程仍在创建对象,数据竞争也会发生。 所以如果你有GVM,就不用担心上面的问题了。像 Java 这样的语言不允许在运行时修改类变量。而且关于垃圾收集的信息并不存储在一个集中的空间中,它单独存储在每个对象本身上。 在Ractor之前的并发实现 为了实现并行性,Ruby on Rails 产生了几个新的 Ruby 进程。 因为每个 Ruby 进程都有自己的 GVL。 但是我们现在有多个解释器,这使得我们的程序效率低下。 同样,Python 的 Flask 也使用这种方法。 至于 Node.js,它也催生了新的 Js 引擎。 但是 Js 没有 GVL,因为它没有线程。 ...

September 12, 2021

Ruby元编程性能

Ruby元编程性能 2015 年,Pragtob 写了一篇关于 Ruby 元编程的贴子。 好吧,您可能想知道为什么我要谈论五年前写的博客,在一个计算机科学正在以不断加快的速度发展的时代。 我搜索了它,因为在工作中我们遇到了这个问题。 在工作中我们使用 Cocoapods 来进行依赖管理。在 Pod 很少的项目中,您不会注意到 Cocoapods 的速度。但是,假设有 600 多个Pod会是什么样的呢?仅 Cocoapods 生成 XCode 项目文件的时间就可能是半分钟!我们设法将性能问题缩小到 this 非常 Ruby 文件。从表面上看,它是无害的。有一个辅助方法可以使用元编程生成其他方法,省去了手动编写排序结果、记忆等事情的麻烦……但是,也有一些方法仅返回一个常量字符串,但也使用了这个辅助方法。使用 define_method 定义的方法开销很小,但是当该方法被调用数万次时,开销足够大,可以使用一些Monkey Patching来优化它。我修补了那些使用 define_method 但简单地返回一个常量字符串的方法。使用简单的 def 重新定义这些方法导致了 5 秒的优化。 5s 听起来可能不多,但在编程世界中,它就像 3 年! 通常,故事到这里就结束了。但是,我决定深入挖掘。你看,我可以从使用 def 重新定义方法中挤出 5 秒。 Ruby 解释器不能首先做类似的事情吗?我查看了 Ruby 解释器源代码,发现用普通 def 定义的方法和用 define_method 定义的方法确实区别对待。对于def,源代码是这里。 define_method 源代码是 here。主要区别在于def函数的类型是VM_METHOD_TYPE_CFUNC,而define_method的类型是VM_METHOD_TYPE_BMETHOD。不幸的是,我没有发现为什么VM_METHOD_TYPE_CFUNC 比VM_METHOD_TYPE_BMETHOD 快,我也不知道为什么它们是不同的类型。在网上快速搜索也无济于事。所以我只好放弃了这件事。然而,我确实通过这个过程对 Ruby 有了更多的了解。我现在知道默认类是 kernel,你在任何类之外定义的所有东西都会进入内核。而类类型实际上也是……一个类! Ruby 中的符号之所以唯一,是因为 rb_intern 将字符串转换为内部的 ID 类型,相同的字符串转换为相同的 ID。 Ruby 维护一个中央函数表,以确定您正在调用哪个函数、函数可见性和它们所属的类与函数本身一起存储。 测试 好吧,如果您对 Ruby 3.0 中的元编程性能感兴趣,在 Pragtob 的帖子发布 5 年后。 这是测试它的代码。 你需要 benchmark-ips gem 来运行它。 ...

September 5, 2021