Порівняння швидкості Python vs Julia


10

Я спробував порівняти ці два фрагменти і побачити, скільки ітерацій можна зробити за одну секунду. Виявляється, Юлія досягає 2,5 мільйонів ітерацій, тоді як Python 4 мільйони. Хіба Юлія не повинна бути швидшою. А може, ці два фрагменти не рівнозначні?

Пітон:

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
Також зверніть увагу, що це якесь порівняння швидкості у бідній людині, чи не так? Сьогодні ви можете змусити Python та Julia працювати приблизно з однаковою швидкістю з належною кількістю мотивації (на обох кінцях). Якщо ви робите це для того, щоб вибрати будь-яку з мов, подивіться, з якою вам легше подумати. Ви можете оптимізувати це пізніше, коли вам це справді потрібно.
norok2

@ norok2 Це справедливо для деяких кодів, але не для інших. Якщо ви зможете перетворити код Python у виклик до функції бібліотеки, написаної швидкою мовою, або якщо він підтримується numba, або щось подібне, можливо, але в іншому випадку Python значно повільніше.
ДНФ

@DNF Є деякі речі, де Python швидший, а інші, де Юлія швидша. Я впевнений, що ви можете знайти приклади обох. Надмірно ігноруючи повну картину можна сказати, що Python "значно" (що б це не означало) повільніше через відносно дорогі явні циклічні та функціональні виклики. Звичайно, якщо це ваш робочий кінь, ніж, можливо, вам краще з Юлією. Однак якщо ви скористаєтеся правильними інструментами, ви можете отримати однаково швидко в Python. Чи варто вивчити ці інструменти чи краще вивчити іншу мову. Важко сказати.
norok2

1
Я використовую обидві мови, і хоча є "деякі" приклади того, що обидві швидкості, баланс значно з одного боку. Це просто наслідок того, що Python інтерпретується і навряд чи зосереджується на виконанні, тоді як Джулія сильно фокусується на виконанні. Насправді це дуже схоже на те, що сказати, що Python такий же швидкий, як C. Це було б дуже дивно, якби не було суттєвої різниці, і це значно підірве призначення Юлії.
ДНФ

Відповіді:


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
}

Компілятор бачить цикл, з'ясовує, що результат щоразу однаковий, і просто повертає це постійне значення, а не виконувати цикл. Що, звичайно, займає нуль часу.


Це 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

Ну, це не те, що я спостерігаю у своїй системі:

Пітон 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% швидше.
Bogumił Kamiński
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.