我试图了解Ruby的性能,遇到了这个SO线程,其中一个答案提到"方法调用,Ruby中最常见的操作之一,特别慢。"
另一个线程提到,"它对方法进行"延迟查找",以实现灵活性。这大大降低了速度。它还必须记住每个上下文的名称,以便进行eval,因此其帧和方法调用较慢。"
有人能更详细地解释为什么Ruby方法调用特别慢,并详细说明第二个线程吗?我不完全确定什么是延迟查找,也不知道为什么它很慢,我也不知道每个上下文的名称意味着什么,也不清楚它与帧和方法调用之间的关系。
我(可能不正确)的理解是,由于方法可以在运行时添加或修改,Ruby解释器永远不会"记住"如何运行特定的方法,所以它必须在程序运行时每次查找方法,这就是方法调用缓慢的意思。但修正和更技术性的解释会很好。
编译语言通常具有快速的方法调度,因为调用代码知道类vtable的索引,vtable是一个方法指针数组。只需几次指针取消引用后,调用代码就可以直接跳转到方法中。编译器创建vtable,并将源代码中的每个方法名称替换为vtable中方法的数字索引。
Ruby等动态语言通常具有缓慢的方法调度,因为调用代码具有方法的名称,而不是指针(也不是指向包含指针的数组的索引)。调用代码必须向对象询问其类,然后必须询问该类是否有该名称的方法,如果没有,则在祖先链上向上询问每个祖先是否有该名字的方法(这就是编译器在编译语言中所做的,这就是编译慢而方法调度快的原因)。动态语言必须执行数十到数百条机器指令来搜索对象的类和对象的所有祖先类,而不是只花费几条机器指令就可以调用一个方法。每个类都有一个名称->方法的HashTable,但具有字符串键的HashTables比具有整数索引的数组慢一个数量级。
当然,有一些方法可以在动态语言中优化方法调度。在Ruby中,这就是JRuby、Rubinius和IronRuby正在做的工作。但这是另一个问题的主题。