Сводка
"Поскольку издержки при вызове функции в Python намного больше, чем в Ruby."
Подробности
Будучи микробенчмарком, это действительно мало что говорито производительности любого языка в правильном использовании.Вероятно, вы захотите переписать программу, чтобы воспользоваться преимуществами Python и Ruby, но это иллюстрирует одно из слабых мест Python на данный момент.Основная причина различий в скорости связана с накладными расходами при вызове функций.Я сделал несколько тестов, чтобы проиллюстрировать.Ниже приведен код и более подробная информация.Для тестов Python я использовал 2000 для обоих параметров gcd.
Interpreter: Python 2.6.6
Program type: gcd using function call
Total CPU time: 29.336 seconds
Interpreter: Python 2.6.6
Program type: gcd using inline code
Total CPU time: 13.194 seconds
Interpreter: Python 2.6.6
Program type: gcd using inline code, with dummy function call
Total CPU time: 30.672 seconds
Это говорит нам о том, что вычисление, выполняемое функцией gcd, больше всего влияет на разницу во времени, а сам вызов функции.В Python 3.1 разница аналогична:
Interpreter: Python 3.1.3rc1
Program type: gcd using function call
Total CPU time: 30.920 seconds
Interpreter: Python 3.1.3rc1
Program type: gcd using inline code
Total CPU time: 15.185 seconds
Interpreter: Python 3.1.3rc1
Program type: gcd using inline code, with dummy function call
Total CPU time: 33.739 seconds
Опять же, фактический расчет не самый большой вклад, это сам вызов функции.В Ruby накладные расходы на вызов функции намного меньше.(Примечание: мне пришлось использовать меньшие параметры (200) для версий программ на Ruby, потому что профилировщик Ruby действительно замедляет производительность в реальном времени. Однако это не влияет на производительность процессорного времени.)
Interpreter: ruby 1.9.2p0 (2010-08-18 revision 29036) [i486-linux]
Program type: gcd using function call
Total CPU time: 21.66 seconds
Interpreter: ruby 1.9.2p0 (2010-08-18 revision 29036) [i486-linux]
Program type: gcd using inline code
Total CPU time: 21.31 seconds
Interpreter: ruby 1.8.7 (2010-08-16 patchlevel 302) [i486-linux]
Program type: gcd using function call
Total CPU time: 27.00 seconds
Interpreter: ruby 1.8.7 (2010-08-16 patchlevel 302) [i486-linux]
Program type: gcd using inline code
Total CPU time: 24.83 seconds
Обратите внимание, что ни Ruby 1.8, ни 1.9 не сильно страдают от вызова функции gcd - вызов функции и встроенная версия более или менее равны.Ruby 1.9 кажется немного лучше, с меньшей разницей между вызовом функции и встроенными версиями.
Таким образом, ответ на вопрос: «потому что издержки вызова функции в Python намного больше, чем в Ruby».
Код
# iter_gcd -- Python 2.x version, with gcd function call
# Python 3.x version uses range instead of xrange
from sys import argv,stderr
def gcd(m, n):
if n > m:
m, n = n, m
while n != 0:
rem = m % n
m = n
n = rem
return m
def main(a1, a2):
comp = 0
for j in xrange(a1, 1, -1):
for i in xrange(1, a2):
comp += gcd(i,j)
print(comp)
if __name__ == '__main__':
if len(argv) != 3:
stderr.write('usage: {0:s} num1 num2\n'.format(argv[0]))
exit(1)
else:
main(int(argv[1]), int(argv[2]))
# iter_gcd -- Python 2.x version, inline calculation
# Python 3.x version uses range instead of xrange
from sys import argv,stderr
def main(a1, a2):
comp = 0
for j in xrange(a1, 1, -1):
for i in xrange(1, a2):
if i < j:
m, n = j, i
else:
m, n = i, j
while n != 0:
rem = m % n
m = n
n = rem
comp += m
print(comp)
if __name__ == '__main__':
if len(argv) != 3:
stderr.write('usage: {0:s} num1 num2\n'.format(argv[0]))
exit(1)
else:
main(int(argv[1]), int(argv[2]))
# iter_gcd -- Python 2.x version, inline calculation, dummy function call
# Python 3.x version uses range instead of xrange
from sys import argv,stderr
def dummyfunc(n, m):
a = n + m
def main(a1, a2):
comp = 0
for j in xrange(a1, 1, -1):
for i in xrange(1, a2):
if i < j:
m, n = j, i
else:
m, n = i, j
while n != 0:
rem = m % n
m = n
n = rem
comp += m
dummyfunc(i, j)
print(comp)
if __name__ == '__main__':
if len(argv) != 3:
stderr.write('usage: {0:s} num1 num2\n'.format(argv[0]))
exit(1)
else:
main(int(argv[1]), int(argv[2]))
# iter_gcd -- Ruby version, with gcd function call
def gcd(m, n)
if n > m
m, n = n, m
end
while n != 0
rem = m % n
m = n
n = rem
end
return m
end
def main(a1, a2)
comp = 0
a1.downto 2 do
|j|
1.upto a2-1 do
|i|
comp += gcd(i,j)
end
end
puts comp
end
if __FILE__ == $0
if ARGV.length != 2
$stderr.puts('usage: %s num1 num2' % $0)
exit(1)
else
main(ARGV[0].to_i, ARGV[1].to_i)
end
end
# iter_gcd -- Ruby version, with inline gcd
def main(a1, a2)
comp = 0
a1.downto 2 do |j|
1.upto a2-1 do |i|
m, n = i, j
if n > m
m, n = n, m
end
while n != 0
rem = m % n
m = n
n = rem
end
comp += m
end
end
puts comp
end
if __FILE__ == $0
if ARGV.length != 2
$stderr.puts('usage: %s num1 num2' % $0)
exit(1)
else
main(ARGV[0].to_i, ARGV[1].to_i)
end
end
Тестовые прогоны
Наконец, команды, используемые для запуска Python и Ruby с профилированием для получения чисел для сравнения, были pythonX.X -m cProfile iter_gcdX.py 2000 2000
для Python и rubyX.X -rprofile iter_gcdX.rb 200 200
для Ruby.Причина разницы в том, что профилировщик Ruby добавляет много накладных расходов.Результаты все еще действительны, потому что я сравниваю разницу между вызовом функции и встроенным кодом, а не разницу между Python и Ruby как таковым.
См. Также
Почему Pythonмедленнее по сравнению с Ruby даже с этим очень простым «тестом»?
Что-то не так с этим кодом Python, почему он работает так медленно по сравнению с ruby?
Игра по тестированию компьютерного языка
Поиск в Google: вызов функции ruby python быстрее