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 来运行它。 ...