Мне любопытно, почему Раку так плохо манипулирует многомерными массивами. Я сделал быстрый тест, инициализирующий 2-мерную матрицу в Python, C # и Raku, и прошедшее время на удивление велико для последующего.
Для раку
my @grid[4000;4000] = [[0 xx 4000] xx 4000];
# Elapsed time 42 seconds !!
Для питона
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
Я делаю не так? Кажется, слишком большая разница.
performance
raku
Javi
источник
источник
@grid[4000;4000]
), код Python не использует фасонный массив, и если вы попробуете то же самое в Raku, вы получите намного лучшее время назад:my @grid = [[0 xx 4000] xx 4000];
это означает, что вы должны получить доступ с помощью@grid[0][0]
не@grid[0;0]
. Я думаю, что это в основном потому, что фигурные массивы все еще находятся в стадии разработки.@grid[1000;1000] = [[0 xx 1000]xx1000]
ушло 12 секунд.@grid = [[0 xx 1000]xx1000]
взял 0,6, так что ... да. Я бы избегал фигурных массивов.my @grid = [[$++ xx 100] xx 100]; say @grid[0;1]; say @grid[1;1]
возвращает 1 и 101 соответственноОтветы:
Первоначальное прямое сравнение
Я начну с кода, который гораздо ближе к вашему коду Python, чем к вашему собственному переводу. Я думаю, что код Raku, который наиболее прямо эквивалентен вашему Python:
Этот код объявляет идентификатор без сигилов 1 . Это:
Капли "шейпинг" (
[4000;4000]
вmy @table[4000;4000]
). Я уронил его, потому что ваш код на Python этого не делает. Формирование дает преимущества, но влияет на производительность. 2Использует связывание вместо назначения . Я переключился на связывание, потому что ваш код Python выполняет связывание, а не присваивание. (Python не делает различий между ними.) Хотя подход Raku по присваиванию дает фундаментальные преимущества, которые стоит иметь для общего кода, он имеет последствия для производительности. 3
Этот код, с которого я начал свой ответ, все еще медленный.
Во-первых, код Raku, запускаемый с помощью компилятора Rakudo с декабря 2018 года, примерно в 5 раз медленнее, чем ваш код Python, с использованием интерпретатора Python с июня 2019 года на том же оборудовании. 3
Во-вторых, и код Raku, и код Python работают медленно, например, по сравнению с вашим кодом C #. Мы можем сделать лучше ...
Идиоматическая альтернатива, которая в тысячу раз быстрее
Следующий код стоит рассмотреть:
Несмотря на то, что этот код соответствует условному массиву из 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 000Seq
с в первом измерении, а не 100 000Array
с -say WHAT table[0]
отображает,Seq
а неArray
- но большая часть кода не сможет обнаружить разницу -say table[99_999;99_999]
все равно будет отображаться0
.)5 Некоторые люди думают, что это слабость - признать, что существует более одного способа думать и кодировать решения данных проблем. На самом деле это сила как минимум в трех отношениях. Во-первых, в общем, любая заданная нетривиальная проблема может быть решена многими различными алгоритмами с существенными различиями в профиле производительности. Этот ответ включает в себя подход, уже доступный для годовалого Ракудо, который на практике будет более чем в тысячу раз быстрее, чем Python, в некоторых сценариях. Во-вторых, преднамеренно гибкий и многопарадигмальный язык, такой как Raku, позволяет кодеру (или команде кодеров) выражать решение, которое они считают элегантным и обслуживаемым, или которое просто выполняет свою работу, основываясь на том, что онидумать лучше, а не то, что навязывает язык. В-третьих, производительность Rakudo в качестве оптимизирующего компилятора в настоящее время заметно варьируется. К счастью, он обладает отличным профилировщиком 6 , поэтому можно видеть узкое место и большую гибкость, поэтому можно попробовать альтернативное кодирование, и это может привести к значительно более быстрому коду.
6 Если производительность важна или вы исследуете проблемы с производительностью, обратитесь к странице документации Raku по производительности ; На этой странице представлен ряд параметров, включая использование профилировщика Rakudo.
источник