Чому Раку так погано справляється з багатовимірними масивами?


10

Мені цікаво, чому Раку так погано маніпулює багатовимірними масивами. Я зробив швидкий тест, ініціалізуючи двовимірну матрицю в Python, C # і Raku, і минулий час напрочуд високий для подальшого.

Для Раку

my @grid[4000;4000] = [[0 xx 4000] xx 4000];
# Elapsed time 42 seconds !!

Для Python

table= [ [ 0 for i in range(4000) ] for j in range(4000) ]
# Elapsed time 0.51 seconds

C #

int [,]matrix = new int[4000,4000];
//Just for mimic same behaviour
for(int i=0;i<4000;i++)
   for(int j=0;j<4000;j++)
       matrix[i,j] = 0;
# Elapsed time 0.096 seconds

Я помиляюся? Здається, занадто велика різниця.


5
Це лише повільно для формованих багатовимірних масивів (EG, де ви це визначаєте @grid[4000;4000]), код python не використовує фігурний масив, і ви намагаєтесь те саме в Raku, ви отримуєте набагато кращий час назад: my @grid = [[0 xx 4000] xx 4000]; це означає, що вам потрібно мати доступ з @grid[0][0]ні @grid[0;0]. Я думаю, що це здебільшого тому, що сформовані масиви все ще працюють.
Scimon Proctor

1
На моїй машині @grid[1000;1000] = [[0 xx 1000]xx1000]пройшло 12 секунд. @grid = [[0 xx 1000]xx1000]взяв 0,6 так ... так. Я б уникав фігурних масивів.
Scimon Proctor

5
@Scimon ви можете фактично використовувати аксесуар [;] для неоформлених масивів. my @grid = [[$++ xx 100] xx 100]; say @grid[0;1]; say @grid[1;1]повертає 1 і 101 відповідно
користувач0721090601

Дивовижно! Це полегшує справи.
Scimon Proctor

2
Сформовані багатовимірні масиви ще не отримали корисної оптимізації, що отримали багато інших областей Ракудо.
Елізабет Маттійсен

Відповіді:


13

Початкове пряме порівняння

Почну з коду, який набагато тісніше узгоджується з вашим кодом Python, ніж власний переклад. Я думаю, що код Раку, який найбільш прямо еквівалентний вашому Python:

my \table = [ [ 0 for ^4000 ] for ^4000 ];
say table[3999;3999]; # 0

Цей код оголошує ідентифікатор 1 без сигналів . Це:

  • Краплі "формуючи" ( [4000;4000]in my @table[4000;4000]). Я скинув його, тому що ваш код Python цього не робить. Формування надає переваги, але має наслідки для продуктивності. 2

  • Використовує прив'язку замість призначення . Я перейшов на прив’язку, тому що ваш код Python виконує обов'язковість, а не призначення. (Python не розрізняє обох.) Хоча підхід до призначення Раку приносить основні переваги, які варто мати для загального коду, він має наслідки для продуктивності. 3


Цей код, з якого я почав свою відповідь, все ще повільний.

По-перше, код Raku, запускається через компілятор Rakudo з грудня 2018 року, приблизно в 5 разів повільніше, ніж ваш код Python, використовуючи інтерпретатор Python з червня 2019 року, на тому ж апаратному забезпеченні. 3

По-друге, і код Раку, і код Python повільні, наприклад, порівняно з кодом C #. Ми можемо зробити краще ...

Ідіоматична альтернатива, яка в тисячу разів швидша

Наступний код варто врахувати:

my \table = [ [ 0 xx Inf ] xx Inf ];
say table[ 100_000; 100_000 ]; # 0

Незважаючи на цей код, відповідний умовному масиву 10 мільярдів елементів, а не лише 16 мільйона елементів у вашому коді Python та C #, час його настінної годинникової роботи не перевищує половини, ніж код Python, і лише у 5 разів повільніше, ніж C # код. Це говорить про те, що Ракудо виконує код Раку в тисячу разів швидше, ніж еквівалентний код Python, і в сто разів швидше, ніж код C #.

Код Raku виявляється набагато швидшим, тому що таблиця ліниво ініціалізується за допомогою xx Inf. 4 Єдина значна робота виконується з запуску sayлінії. Це спричиняє створення 100 000 перших розмірних масивів, а потім заповнення лише 100 000-го масиву другого розміру 100 000 елементами, щоб sayвідобразити 0утримуваний в останньому елементі масив.

Існує більше, ніж один спосіб зробити це

Одне питання, що лежить в основі вашого питання, полягає в тому, що завжди існує більше ніж один спосіб зробити це. 5 Якщо ви зіткнулися з низькою продуктивністю для коду, де швидкість є критичною, кодування його по-різному, як я це зробив, може призвести до кардинальної зміни. 6

(Ще один дуже хороший варіант - задати питання ТАК ...)

Майбутнє

Рака ретельно розроблена , щоб бути дуже optimiz стану , тобто в стані в один день працювати набагато швидше даний достатньою роботу компілятора в протягом найближчих років , ніж, скажімо, Perl 5 або Python-теоретично може, коли - небудь працювати, якщо вони не проходять через наземний оновлення та роки відповідної роботи компілятора.

Дещо в порядку аналогія - це те, що відбулося з роботою Java протягом останніх 25 років. Rakudo / NQP / MoarVM проходить приблизно на півдорозі процесу дозрівання, який пройшов стек Java.

Виноски

1 Я міг би написати my $table := .... Але декларації форми my \foo ...виключають врахування сигілів та дозволяють використовувати =замість того, :=що потрібно з ідентифікатором sigil'd. (Як бонус, "розрізання сигіли" призводить до отримання ідентифікатора вільного сигілу, знайомого кодерам на багатьох мовах, які не використовують сигіли, що, звичайно, включає Python та C #.)

2 Формування може в один день призвести до більш швидких операцій масиву для деякого коду. Тим часом, як згадується в коментарях до вашого запитання, зараз явно робиться навпаки, значно сповільнюючи це. Я думаю, що це значною мірою тому, що кожен доступ до масиву наївно динамічно перевіряється на межі, повільно все знижується, і також не було зусиль використовувати фіксований розмір, щоб допомогти прискорити роботу. Крім того, коли я спробував придумати швидкий спосіб вирішення вашого коду, мені не вдалося знайти його за допомогою масиву фіксованого розміру через те, що багато операцій з масивами фіксованого розміру в даний час не виконуються. Знову ж таки, вони, сподіваємось, будуть реалізовані одного дня, але, мабуть, не були достатньою больовою точкою для того, щоб хтось працював над їх виконанням на сьогодні.

3 На момент написання цього повідомлення TIO використовує Python 3.7.4, починаючи з червня 2019 року, і Rakudo v2018.12, починаючи з грудня 2018 року. Продуктивність Ракудо в даний час покращується значно швидше, ніж офіційний перекладач Python 3, тому я б очікуємо, що розрив між останнім ракудо та останнім Python, коли Ракудо повільніше, буде значно вужчим, ніж зазначено у цій відповіді. Зокрема, поточна робота суттєво покращує виконання завдань.

4 xx за замовчуванням для ледачої обробки, але деякі вирази змушують прагнути оцінки через мовну семантику чи поточні обмеження компілятора. У річному віці 2018 року.12 Ракудо, щоб вираз форми [ [ foo xx bar ] xx baz ]залишався ледачим і не був змушений оцінювати прагнення, і те, bar і bazповинно бути Inf. Навпаки, my \table = [0 xx 100_000 for ^100_000]лінивий без жодної користі Inf. (Останній код насправді зберігає 100 000 Seqс у першому вимірі, а не 100 000 Arrayс - say WHAT table[0]дисплеї, Seqа не Array- але більшість кодів не зможе помітити різницю - say table[99_999;99_999]все одно відображатиметься 0.)

5 Деякі люди вважають, що слабкість визнати, що існує більше ніж один спосіб думати і кодувати рішення заданих проблем. Насправді це сила принаймні в трьох відношеннях. По-перше, загалом будь-яку задану нетривіальну проблему можна вирішити багатьма різними алгоритмами з різкими відмінностями у характеристиці продуктивності. Ця відповідь включає підхід, вже наявний з річним Ракудо, який буде в тисячі разів швидшим, ніж Python на практиці в деяких сценаріях. По- друге, свідомо гнучкий і мульти-парадигми мови як Раку дозволяє кодувати (або команда кодеров) , щоб висловити рішення , яке вони вважають елегантний і ремонтопрігодни, або просто отримує роботу, грунтуючись на тому, що вонидумати найкраще, а не те, що нав'язує мова. По-третє, продуктивність Rakudo як оптимізуючого компілятора в даний час помітно відрізняється. На щастя, він має чудовий профілер 6 , тому можна побачити, де знаходиться вузьке місце, і велику гнучкість, тому можна спробувати альтернативне кодування, і це може створити набагато швидший код.

6 Якщо важливість роботи важлива або ви розслідуєте проблеми з продуктивністю, перегляньте сторінку документа Raku щодо продуктивності ; сторінка охоплює цілий ряд варіантів, включаючи використання профіля Rakudo.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.