Ответ 1
Резюме
"Так как служебная нагрузка функции в 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?