Сравнение скорости Питона и Юлии

9

Я попытался сравнить эти два фрагмента и посмотреть, сколько итераций можно выполнить за одну секунду. Оказывается, что Юлия достигает 2,5 миллиона итераций, тогда как Python 4 миллиона. Разве Джулия не должна быть быстрее? Или, может быть, эти два фрагмента не эквивалентны?

Python:

t1 = time.time()
i = 0
while True:
    i += 1
    if time.time() - t1 >= 1:
        break

Юлия:

function f()
    i = 0
    t1 = now()
    while true
        i += 1
        if now() - t1 >= Base.Dates.Millisecond(1000)
            break
        end
    end
    return i
end
Михась
источник
4
Я не уверен, как работает Джулия, но, похоже, вам нужно создавать новый объект для каждого сравнения, в то время как Python выполняет простые целочисленные сравнения.
Чепнер
1
Также обратите внимание, что это сравнение скорости человека какого-то бедного, не так ли? В настоящее время вы можете заставить Питона и Джулию бегать примерно с одинаковой скоростью с достаточной мотивацией (на обоих концах). Если вы делаете это, чтобы выбрать один из языков, подумайте, на каком из них вам будет легче думать. Вы можете оптимизировать это позже, когда вам это действительно нужно.
norok2
@ norok2 Это верно для некоторых кодов, но не для других. Если вы можете превратить код Python в вызов библиотечной функции, написанной на быстром языке, или если она поддерживается numba, или чем-то подобным, то, возможно, но в остальном Python значительно медленнее.
DNF
@DNF Есть некоторые вещи, где Python быстрее, а некоторые другие, где Джулия быстрее. Я уверен, что вы можете найти примеры обоих. Чрезвычайно игнорируется полная картина, чтобы сказать, что Python «значительно» (что бы это ни значило) медленнее только из-за относительно дорогих явных циклов и вызовов функций. Конечно, если это ваша рабочая лошадка, то, возможно, вам лучше с Джулией. Однако, если вы используете правильные инструменты, вы можете получить одинаково быстро в Python. Стоит ли изучать эти инструменты или лучше изучать другой язык. Трудно сказать.
norok2
1
Я использую оба языка, и хотя есть «некоторые» примеры того, как они быстрее, баланс значительно с одной стороны. Это просто следствие того, что Python интерпретируется и практически не фокусируется на производительности, в то время как Джулия уделяет большое внимание производительности. На самом деле это все равно, что сказать, что Python так же быстр, как и C. Это было бы очень странно, если бы не было существенной разницы, и это подорвало бы большую часть цели Джулии.
DNF

Ответы:

9

Это своего рода странное сравнение производительности, поскольку обычно измеряется время, необходимое для вычисления чего-то существенного, вместо того, чтобы видеть, сколько тривиальных итераций можно выполнить за определенное время. У меня были проблемы с тем, чтобы заставить работать ваши коды Python и Julia, поэтому я изменил код Julia для работы и просто не запустил код Python. Как отметил @chepner в комментарии, использование now()и сравнение времени с DateTimeобъектами довольно дорого. Функция Python time.time()просто возвращает значение с плавающей точкой. Оказывается, есть функция Julia, time()которая делает то же самое:

julia> time()
1.587648091474481e9

Вот время вашей исходной f()функции (модифицированной для работы) в моей системе:

julia> using Dates

julia> function f()
           i = 0
           t1 = now()
           while true
               i += 1
               if now() - t1 >= Millisecond(1000)
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
4943739

Он сделал почти 5 миллионов итераций, прежде чем время истекло. Как я уже сказал, я не смог заставить ваш Python-код работать в моей системе без значительных хлопот (что я и не удосужился сделать). Но вот версия, f()которая использует time()вместо этого, что я буду образно называть g():

julia> function g()
           i = 0
           t1 = time()
           while true
               i += 1
               if time() - t1 >= 1
                   break
               end
           end
           return i
       end
g (generic function with 1 method)

julia> g()
36087637

Эта версия сделала 36 миллионов итераций. Значит, Джулия быстрее зацикливается? Ура! Ну, на самом деле основная работа в этом цикле - это вызовы time()так ... Джулия быстрее генерирует много time()вызовов!

Почему странно это время? Как я уже сказал, большая часть реальной работы здесь зовет time(). Остальная часть цикла ничего не делает. В оптимизируемом скомпилированном языке, если компилятор видит цикл, который ничего не делает, он полностью его устраняет. Например:

julia> function h()
           t = 0
           for i = 1:100_000_000
               t += i
           end
           return t
       end
h (generic function with 1 method)

julia> h()
5000000050000000

julia> @time h()
  0.000000 seconds
5000000050000000    

Вау, ноль секунд! Как это возможно? Что ж, давайте посмотрим на код LLVM (вроде машинного кода, но для воображаемой машины, которая используется в качестве промежуточного представления), это понижается до:

julia> @code_llvm h()

;  @ REPL[16]:1 within `h'
define i64 @julia_h_293() {
top:
;  @ REPL[16]:6 within `h'
  ret i64 5000000050000000
}

Компилятор видит цикл, выясняет, что результат каждый раз один и тот же, и просто возвращает это постоянное значение вместо фактического выполнения цикла. Что, конечно, занимает нулевое время.

StefanKarpinski
источник
Это BogoMips языков программирования
norok2
1
Правильно, но bogomips используются для измерения процессора, а не языка программирования. Но конечно, это вещь, которую можно измерить.
Стефан Карпински
4

Вы, вероятно, хотите использовать time_nsфункцию в Джулии:

function f()
    i = 0
    t1 = time_ns()
    while true
        i += 1
        if time_ns() - t1 >= 10^9
            break
        end
    end
    return i
end

На моем компьютере он работает в 10 раз быстрее, чем Python.

Богумил Каминьский
источник
4

Ну, это не то, что я наблюдаю в моей системе:

Python 3.7.7

Python 3.7.7 (default, Mar 26 2020, 15:48:22) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import time                                                                                                                                                       

In [2]: def f(): 
   ...:     t1 = time.time() 
   ...:     i = 0 
   ...:     while True: 
   ...:         i += 1 
   ...:         if time.time() - t1 >= 1: 
   ...:             return i 
   ...:                                                                                                                                                                   

In [3]: f()                                                                                                                                                               
Out[3]: 4676268


Юлия 1.4.0:

julia> using Dates

julia> function f()
           i = 0
           t1 = now()
           while true
               i += 1
               if now() - t1 >= Dates.Millisecond(1000)
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
6339528

но обратите внимание, что простое использование time(то есть сравнение простых чисел) все еще быстрее:

julia> function f()
           i = 0
           t1 = time()
           while true
               i += 1
               if time() - t1 >= 1
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
24742703
Франсуа Февотт
источник
ты не должен использовать time.perf_counter_ns()в Python?
norok2
Использование time.perf_counter_ns ничего не меняет (по крайней мере, в моей системе) для этого теста. Я предполагаю, что при измерении разницы во времени порядка 1 секунды точность измерения времени не имеет большого значения. Здесь важно только время, необходимое для измерения и сравнения полученных объектов (а также эффективность самих циклов).
Франсуа Февотт
В Julia время измерения имеет значение, поэтому в моем коде я использовал time_nsне так, timeкак на ~ 30% быстрее.
Богумил Каминский