Первоначальное прямое сравнение
Я начну с кода, который гораздо ближе к вашему коду Python, чем к вашему собственному переводу. Я думаю, что код Raku, который наиболее прямо эквивалентен вашему Python:
my \table = [ [ 0 for ^4000 ] for ^4000 ];
say table[3999;3999]; # 0
Этот код объявляет идентификатор без сигилов 1 . Это:
Капли "шейпинг" ( [4000;4000]
в my @table[4000;4000]
). Я уронил его, потому что ваш код на Python этого не делает. Формирование дает преимущества, но влияет на производительность. 2
Использует связывание вместо назначения . Я переключился на связывание, потому что ваш код Python выполняет связывание, а не присваивание. (Python не делает различий между ними.) Хотя подход Raku по присваиванию дает фундаментальные преимущества, которые стоит иметь для общего кода, он имеет последствия для производительности. 3
Этот код, с которого я начал свой ответ, все еще медленный.
Во-первых, код Raku, запускаемый с помощью компилятора Rakudo с декабря 2018 года, примерно в 5 раз медленнее, чем ваш код Python, с использованием интерпретатора Python с июня 2019 года на том же оборудовании. 3
Во-вторых, и код Raku, и код Python работают медленно, например, по сравнению с вашим кодом C #. Мы можем сделать лучше ...
Идиоматическая альтернатива, которая в тысячу раз быстрее
Следующий код стоит рассмотреть:
my \table = [ [ 0 xx Inf ] xx Inf ];
say table[ 100_000; 100_000 ]; # 0
Несмотря на то, что этот код соответствует условному массиву из 10 миллиардов элементов, а не простому элементу из 16 миллионов элементов в вашем коде Python и C #, время выполнения его на настенном такте меньше, чем половина кода Python, и всего в 5 раз медленнее, чем C # код. Это говорит о том, что Rakudo выполняет код Raku в тысячу раз быстрее, чем эквивалентный код 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 ...
исключают возможность рассмотрения сигил и позволяют использовать их =
вместо :=
идентификатора сигилла. (В качестве бонуса «вырезание сигилы» приводит к бесплатному идентификатору, знакомому кодировщикам на многих языках, которые не используют сигилы, которые, конечно, включают в себя Python и C #.)
2 Формирование может однажды привести к более быстрым операциям массива для некоторого кода. Между тем, как уже упоминалось в комментариях к вашему вопросу, в настоящее время он явно делает обратное, значительно замедляя его. Я предполагаю, что это в значительной степени потому, что каждый доступ к массиву в настоящее время наивно динамически проверяется на предмет границ, медленно все сокращается, и также не было никаких попыток использовать фиксированный размер, чтобы ускорить процесс. Кроме того, когда я попытался найти быстрое обходное решение для вашего кода, мне не удалось найти его с использованием массива с фиксированным размером из-за многих операций с массивами с фиксированным размером, которые в настоящее время не реализованы. Опять же, мы надеемся, что они будут реализованы однажды, но, по-видимому, они не стали достаточной проблемой для того, чтобы кто-либо работал над их реализацией на сегодняшний день.
3 На момент написания этой статьи TIO использует Python 3.7.4 с июня 2019 года и Rakudo v2018.12 с декабря 2018 года. Производительность Rakudo в настоящее время улучшается со временем значительно быстрее, чем у официального интерпретатора Python 3, поэтому я бы сказал, ожидайте, что разрыв между последним Rakudo и последним Python, когда Rakudo медленнее, будет значительно меньше, чем указано в этом ответе. В частности, текущая работа значительно улучшает выполнение заданий.
4 по xx
умолчанию используется ленивая обработка, но некоторые выражения требуют тщательной оценки из-за языковой семантики или текущих ограничений компилятора. В годовалом v2018.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, в некоторых сценариях. Во-вторых, преднамеренно гибкий и многопарадигмальный язык, такой как Raku, позволяет кодеру (или команде кодеров) выражать решение, которое они считают элегантным и обслуживаемым, или которое просто выполняет свою работу, основываясь на том, что онидумать лучше, а не то, что навязывает язык. В-третьих, производительность Rakudo в качестве оптимизирующего компилятора в настоящее время заметно варьируется. К счастью, он обладает отличным профилировщиком 6 , поэтому можно видеть узкое место и большую гибкость, поэтому можно попробовать альтернативное кодирование, и это может привести к значительно более быстрому коду.
6 Если производительность важна или вы исследуете проблемы с производительностью, обратитесь к странице документации Raku по производительности ; На этой странице представлен ряд параметров, включая использование профилировщика Rakudo.
@grid[4000;4000]
), код Python не использует фасонный массив, и если вы попробуете то же самое в Raku, вы получите намного лучшее время назад:my @grid = [[0 xx 4000] xx 4000];
это означает, что вы должны получить доступ с помощью@grid[0][0]
не@grid[0;0]
. Я думаю, что это в основном потому, что фигурные массивы все еще находятся в стадии разработки.