Початкове пряме порівняння
Почну з коду, який набагато тісніше узгоджується з вашим кодом 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.
@grid[4000;4000]
), код python не використовує фігурний масив, і ви намагаєтесь те саме в Raku, ви отримуєте набагато кращий час назад:my @grid = [[0 xx 4000] xx 4000];
це означає, що вам потрібно мати доступ з@grid[0][0]
ні@grid[0;0]
. Я думаю, що це здебільшого тому, що сформовані масиви все ще працюють.