Почему вызовы методов Ruby особенно медленны (по сравнению с другими языками)? - PullRequest
21 голосов
/ 20 июня 2011

Я пытаюсь прочитать о производительности Ruby, и наткнулся на этот поток SO , где в одном из ответов упоминается, что "вызовы методов, одна из самых распространенных операций в Ruby, особенно медленные. «

Другой поток упоминает, что "Он выполняет" поздний поиск "для методов, чтобы обеспечить гибкость. Это немного замедляет его. Он также должен запоминать имена для контекста, чтобы обеспечить eval, поэтому его кадры и вызовы методов медленнее. "

Может кто-нибудь объяснить более подробно, почему вызовы методов Ruby являются особенно медленными, и подробно описать второй поток? Я не совсем уверен, что такое поздний поиск или почему он медленный, и я не знаю, что означают имена в контексте или как они связаны с фреймами и вызовами методов.

Мое (возможно, неправильное) понимание состоит в том, что, поскольку методы могут быть добавлены или изменены во время выполнения, интерпретатор Ruby никогда не может "запомнить", как запустить тот или иной метод, поэтому он должен искать метод каждый раз, когда выполняется программа и это означает, что вызовы методов являются медленными. Но исправления и более технические объяснения были бы хороши.

1 Ответ

18 голосов
/ 20 июня 2011

Скомпилированные языки часто имеют быструю диспетчеризацию метода , потому что вызывающему коду известен индекс в классе vtable, который является массивом указателей на методы. После нескольких разыменований указателя вызывающий код может перейти прямо в метод. Компилятор создает виртуальную таблицу и заменяет каждое имя метода в исходном коде числовым индексом метода в виртуальной таблице.

Динамические языки, такие как Ruby, часто имеют медленную диспетчеризацию метода, потому что вызывающий код имеет имя для метода, а не указатель (или индекс в массиве, содержащем указатели). Вызывающий код должен запросить у объекта свой класс, затем спросить у класса, есть ли у него метод с таким именем, а если нет, пройти вверх по цепочке предков, спрашивая каждого предка, есть ли у него метод с таким именем ( это то, что компилятор делает на скомпилированном языке, поэтому компиляция происходит медленно, а диспетчеризация метода происходит быстро). Вместо того чтобы несколько разыменовывать указатель, требующий нескольких машинных инструкций для вызова метода, динамический язык должен выполнять от десятков до сотен машинных инструкций для поиска класса объекта и всех классов-предков объекта для метода. У каждого класса есть HashTable имен -> методы, но HashTable со строковыми ключами на порядок медленнее, чем массивы с целочисленными индексами.

Конечно, есть способы оптимизировать диспетчеризацию методов в динамических языках. В Ruby над этим работают JRuby, Rubinius и IronRuby. Но это тема для другого вопроса.

...