CPython особенно медленный, потому что у него нет оптимизатора Just in Time (поскольку он является эталонной реализацией и в некоторых случаях выбирает простоту над производительностью). Unladen Swallow - это проект по добавлению JIT с поддержкой LLVM в CPython, обеспечивающий значительное ускорение. Вполне возможно, что Jython и IronPython намного быстрее, чем CPython, а также поддерживаются сильно оптимизированными виртуальными машинами (JVM и .NET CLR).
Одна вещь, которая, вероятно, сделает Python медленнее, однако, это то, что он динамически типизирован, и есть тонны поиска для каждого доступа к атрибуту.
Например, вызов f
для объекта A
вызовет возможные поиски в __dict__
, вызовы __getattr__
и т. Д., А затем, наконец, вызовет __call__
для вызываемого объекта f
.
Что касается динамической типизации, существует множество оптимизаций, которые можно выполнить, если вы знаете, с каким типом данных вы имеете дело. Например, в Java или C, если у вас есть прямой массив целых чисел, которые вы хотите суммировать, код окончательной сборки может быть таким же простым, как получение значения по индексу i
, добавление его к accumulator
, а затем увеличение i
.
В Python очень сложно сделать код таким оптимальным. Скажем, у вас есть объект подкласса списка, содержащий int
s. Прежде чем добавить что-либо, Python должен вызвать list.__getitem__(i)
, затем добавить это к «аккумулятору», вызвав accumulator.__add__(n)
, а затем повторить. Здесь может произойти множество альтернативных поисков, потому что другой поток мог изменить, например, метод __getitem__
, диктат экземпляра списка или диктат класса, между вызовами add или getitem. Даже поиск аккумулятора и списка (и любой переменной, которую вы используете) в локальном пространстве имен вызывает поиск по умолчанию. Эти же накладные расходы применяются при использовании любого определенного пользователем объекта, хотя для некоторых встроенных типов он несколько смягчается.
Стоит также отметить, что примитивные типы, такие как bigint (int в Python 3, long в Python 2.x), list, set, dict и т. Д. И т. Д., - это то, что люди часто используют в Python. Существует множество встроенных операций на этих объектах, которые уже достаточно оптимизированы. Например, для приведенного выше примера вы просто позвоните sum(list)
вместо использования аккумулятора и индекса. Придерживаясь этого, и немного разбирая числа с помощью int / float / complex, у вас, как правило, не будет проблем со скоростью, и если вы это сделаете, то, вероятно, есть небольшая критическая по времени единица (например, функция дайджеста SHA2), которую вы можете просто перейдите на C (или Java-код в Jython). Дело в том, что когда вы кодируете C или C ++, вы тратите лотов времени на то, что вы можете сделать за несколько секунд / строк кода Python. Я бы сказал, что компромисс всегда стоит, за исключением случаев, когда вы занимаетесь чем-то вроде встроенного программирования или программирования в реальном времени и не можете себе этого позволить.