Які смислові особливості Python (та інших динамічних мов) сприяють його повільності?


26

Я не дуже добре знаю Python. Я намагаюся зрозуміти точніше, які саме особливості динамічних мов (à la Python, Lua, Scheme, Perl, Ruby, ....) змушують їх реалізацію бути повільними.

Як конкретний випадок, металообробна техніка Lua 5.3 інтуїтивно зробить Lua досить повільною, але на практиці, як чують , Lua досить швидкий (і швидший, ніж Python).

Також у мене є інтуїція (можливо, неправильна), оскільки пам'ять на поточних процесорах значно повільніша, ніж необроблені обчислення (доступ до пам'яті з кешем пропускає потрібно стільки ж, скільки й сотні арифметичних операцій), динамічна перевірка типу (à la if (value->type != INTEGER_TAG) return;in C parlance) міг працювати досить швидко.

Звичайно, аналіз цілої програми (на зразок впровадження Сталінської схеми ) може зробити динамічну мовну реалізацію, оскільки перекладач працює швидко, але давайте робити вигляд, що спочатку я не встигаю розробити цілий аналізатор програми.

(Я начебто проектую динамічну мову на моєму моніторі MELT , і частина цього буде перекладена на C)



1
Поради щодо ефективності Lua , де пояснюється, чому деякі програми Lua повільні та як їх виправити.
Роберт Харві

Відповіді:


24

Які смислові особливості Python (та інших динамічних мов) сприяють його повільності?

Немає.

Виконання мовних реалізацій - це функція грошей, ресурсів та кандидатських дисертацій, а не особливості мови. Self є набагато більш динамічним, ніж Smalltalk і трохи більш динамічним, ніж Python, Ruby, ECMAScript або Lua, і він мав VM, що перевершував усі існуючі VM Lisp і Smalltalk (насправді, саморозподіл постачався разом з невеликим перекладачем Smalltalk, написаним у Self , і навіть це було швидше, ніж більшість існуючих VM Smalltalk), і було конкурентоспроможним, а іноді навіть швидшим, ніж впровадження C ++ того часу.

Тоді Sun не припинила фінансувати Self, і IBM, Microsoft, Intel та Co. почали фінансувати C ++, і тенденція змінилася. Розробники Self залишили Sun створити власну компанію, де вони використовували технологію, розроблену для Self VM, щоб створити один з найшвидших віртуальних машин Smalltalk коли-небудь (Animorphic VM), а потім Sun викупила цю компанію, і трохи змінену версію що Smalltalk VM тепер більше відомий під назвою "HotSpot JVM". За іронією долі, програмісти Java дивляться на динамічні мови, оскільки вони є "повільними", а фактично - Javaйшло повільно, поки не було прийнято динамічну технологію мови. (Так, саме так: JVM HotSpot - це, по суті, Smalltalk VM. Перевірявач байт-коду робить багато перевірки типів, але як тільки байт-код приймається верифікатором, VM, а особливо оптимізатор і JIT насправді не роблять великий інтерес до статичних типів!)

CPython просто не робить багато того, що робить динамічні мови (а точніше динамічну диспетчеризацію) швидкими: динамічна компіляція (JIT), динамічна оптимізація, спекулятивне вбудовування, адаптивна оптимізація, динамічна деоптимізація, динамічний зворотний зв'язок / умовивід. Існує також проблема в тому, що майже вся основна і стандартна бібліотека написана на C, це означає, що навіть якщо ви зробите Python 100x швидше, це вам не дуже допоможе, тому що щось на зразок 95% коду, виконаного Програма Python - це C, а не Python. Якби все було написано в Python, навіть помірні прискорення створювали б ефект лавини, коли алгоритми стають швидшими, а основні структури даних - швидшими, але, звичайно, основні структури даних також використовуються в межах алгоритмів, а основні алгоритми та основні дані структури використовуються скрізь,

Є кілька речей, які, як відомо, погані для мов OO, керованої пам'яттю (динамічні чи ні) в сучасних системах. Захист віртуальної пам’яті та пам’яті може бути вбивцею зокрема для вивезення сміття, а також для роботи системи в цілому. І це абсолютно непотрібно для безпечної для пам’яті мови: навіщо захищати від незаконного доступу до пам’яті, коли в мові немає жодного доступу до пам’яті? Azul придумав використовувати сучасні потужні MMU (Intel Nehalem і новіші, і AMD-еквівалент), щоб допомогти збору сміття замість того, щоб перешкоджати цьому, але, хоча це підтримується процесором, поточні підсистеми пам'яті в основному ОС недостатньо потужні щоб це (саме тому JVM Azul фактично біжить віртуалізувати на голий метал , крім ОС, а не всередині неї).

У проекті Singularity OS Microsoft виміряла вплив на 30% на продуктивність системи при використанні захисту MMU замість системи типу для поділу процесу.

Інша річ, яку Azul зауважив, будуючи свої спеціалізовані процесори Java, - це те, що сучасні основні процесори зосереджуються на абсолютно неправильній справі, намагаючись зменшити витрати на пропуски кешу: вони намагаються зменшити кількість пропусків кешу за допомогою таких завдань, як передбачення гілок, попереднє завантаження пам'яті, і так далі. Але у сильно поліморфній програмі ОО схеми доступу в основному є псевдовипадковими, просто передбачити нічого немає. Отже, всі ці транзистори просто марно витрачаються, а те, що потрібно робити замість цього, - це зменшити вартість кожної пропущеної окремої кеши. (Загальна вартість - це #misses * cost; mainstream намагається збити перше, а Azul - друге.) Java Compute Accelerators Azul може мати 20000 одночасних пропусків кешу в польоті і все ж робити прогрес.

Коли Azul запустився, вони думали, що вони візьмуть кілька нестандартних компонентів вводу / виводу і розробити власне спеціалізоване ядро ​​процесора, але те, що їм насправді потрібно було зробити, було з точністю до навпаки: вони взяли досить стандартний режим відключення 3-адресна ядро ​​RISC на шельфі і розроблено власний контролер пам'яті, MMU та підсистему кешу

tl; dr : "повільність" Python - це не властивість мови, а а) її наївна (первинна) реалізація; і b) факт, що сучасні процесори та ОС спеціально розроблені для швидкого запуску C, і їхніх функцій have для C або не допомагають (кешувати), або навіть активно шкодять (віртуальна пам'ять) продуктивність Python.

І тут ви можете вставити майже будь-яку мову, керовану пам'яттю, з динамічним спеціальним поліморфізмом ... коли мова йде про проблеми ефективної реалізації, навіть Python та Java майже «одна і та ж мова».


У вас є посилання або посилання на Azul?
Базиль Старинкевич

4
Я не погоджуюся, що семантика мови не впливає на її здатність ефективно реалізовуватися. Так, хороша реалізація JIT з перших оптимізації та аналізу класу може зробити величезну поліпшення в продуктивності мови, але в кінці кінців , є певні аспекти семантики , які будуть неминуче в кінцевому підсумку вузькі місця. Незалежно від того, що це вимога С для суворого згладжування покажчиків або вимога Python, щоб операції зі списком виконувались атомно, є певні семантичні рішення, які неминуче призводять до погіршення продуктивності деяких додатків.
Жуль

1
Як осторонь ... чи є у вас посилання на 30% поліпшення сингулярності? Я багато прихильників ОС на основі мовної захисту протягом багатьох років, але ніколи раніше не бачив цієї цифри, і вважаю її досить приголомшливою (цифри, які я дивився в минулому, були ближче до 10%) і цікаво, що вони зробили так багато покращення ...
Jules

5
@MasonWheeler: Тому що там є лише хитрі реалізації Python. Жоден реалізатор Python не витратив навіть мінімальну частину грошей, люди, дослідження та ресурси IBM, Sun, Oracle, Google і Co. витратили на J9, JRockit, HotSpot та Co. Усі 5 реалізацій Python у поєднанні, ймовірно, навіть не мати робочу силу, яку Oracle витрачає саме на смітник. IBM працює над реалізацією Python на базі Eclipse OMR (компонентний VM-кадр із відкритим джерелом, витягнутий з J9), я готовий зробити ставку на те, що його продуктивність буде добре в межах порядку J9
Jörg W Mittag

2
Для запису C є повільним порівняно з Fortran для чисельної роботи, оскільки Fortran виконує суворе згладжування, щоб оптимізатор міг бути більш агресивним.
Майкл Шопсін

8

У той час як поточна реалізація Python (якій бракує багато оптимізацій, виконаних іншими динамічними мовами, наприклад, сучасними реалізаціями Javascript і, як ви зазначаєте, Lua) є джерелом більшості його проблем, у нього є деякі семантичні проблеми, які могли б це зробити складно для реалізації, щоб конкурувати з іншими мовами, принаймні в певних сферах. Деякі, про які варто звернути увагу:

  • Операції зі списком та словником визначаються мовою визначення атомарними. Це означає, що якщо компілятор JIT не зможе довести, що жодна посилання на об'єкт списку не уникнула його поточного потоку (аналіз, який у багатьох випадках складний і неможливий у загальному випадку), він повинен забезпечити серіалізацію доступу до об'єкта (наприклад, через блокування). Реалізація CPython вирішує цю проблему, використовуючи сумнозвісний "глобальний замок інтерпретатора", який запобігає ефективному використанню Python-коду в багатопроцесорних середовищах з багатопотоковими методами, і в той час, як можливі інші рішення, усі вони мають проблеми з продуктивністю.

  • Python не має механізму вказівки на використання об'єктів цінності; все обробляється посиланням, додаючи додаткову непряму туди, де це не обов'язково потрібно. Незважаючи на те, що компілятор JIT може зробити висновок про об'єкти значення в деяких випадках і автоматично оптимізувати це, це неможливо зробити в цілому, і тому код, який ретельно не написано, щоб гарантувати оптимізацію (це дещо чорне мистецтво) постраждає.

  • У Python є evalфункція, що означає, що компілятор JIT не може робити припущення про те, що дії не відбудуться, навіть якщо він виконує аналіз у всій програмі, якщо evalвикористовується один раз. Наприклад, компілятор Python не може припустити, що у класу немає підкласів, і тому девіартуалізує виклики методу, тому що це припущення згодом може бути відхилено за допомогою виклику до eval. Натомість він повинен виконувати перевірки динамічного типу, щоб переконатися, що припущення, зроблені за допомогою власного зібраного коду, не були визнані недійсними перед виконанням цього коду.


3
Останню точку можна пом'якшити, evalвикликавши повторну компіляцію та / або деоптимізацію.
Йорг W Міттаг

4
До речі, це не властиво і Python. Java (а точніше JVM) має динамічне завантаження коду та динамічне посилання, тому аналіз ієрархії класів еквівалентний і вирішенню проблеми зупинки. І все ж HotSpot із задоволенням спекулятивно нав'язує поліморфні методи, і якщо щось в ієрархії класів зміниться, то воно просто поверне їх назад.
Йорг W Міттаг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.