И чо? Новость конкретно про rakudo. И в стартовом сообщении я и напомнил что это такое. Что это компилятор вчерашнего Perl 6, который теперь переименовали в Raku.
При чём здесь «Perl переименовали???» и «Ну так, Perl-то не переименовали.» я вообще не представляю.
Пока что штука немного сомнительной нужности (на мой взгляд).
Релизы на онтопике и так есть, далее они опакечиваются под основные дистрибутивы, на макоси всё ставится, насколько я в курсе, а rakudo star когда-то был 1)сборником из компилятор + пакетник + «полезные» модули; 2)способом установить rakudo на оффтопике.
1 стало менее нужно, а оффтопик не нужно оффтопик не пользуется чудовищной популярностью у энтузиастов, использующих язык. Если уж идти в какую-то сторону, то в сторону упрощения, на мой взгляд, проще уж сделать отдельный инсталлятор под оффтопик и собирать так, чем иметь несколько циклов релизов и делать длинные объяснения в духе «Так-так, язык это такое, а это компилятор, а это виртуалка, а star это компилятор плюс модули, а ещё нет-нет постойте не уходите дослушайте».
Если следить за руками фокусника, то можно узнать, что это не идентичные скрипты.
my int – правильное изменение, я не помню, чтобы оно влияло раньше, но результат налицо:
$ time ./a.raku
real 0m9,802s
user 0m9,835s
sys 0m0,041s
Но почто stub упростил? Его, наоборот, усложнять надо, чтобы хитрый интерпретатор не додумался его выоптимизировать вместе со всем циклом.
Что, похоже, и случается.
Но почто stub упростил? Его, наоборот, усложнять надо, чтобы хитрый интерпретатор не додумался его выоптимизировать вместе со всем циклом.
Во-первых, не интерпретатор, а компилятор в байткод в виртуалку с динамическими оптимизациями…
Не совсем так, это «ложные друзья переводчика», ну или «Если на любом языке писать как на фортране, будет фортран».
return в raku, в отличии от перла, это просто рутина, которая кидает control exception (которое можно красиво отловить и всё такое), и это всё не zero cost, а если ты хочешь просто ret, то тогда ты ничего и не делаешь. Сам вызов не убирается полностью, только JIT 100% вызовов, посмотреть это можно в профайлере.
Что же до int то тут опять таки: в raku честные big integers искоропки реализованные объектами (а ооп здесь полный фарш с мультиметодами, метаобъектным протоколом и всем остальным), поэтому сравнивать их с перловскими интами, которые переполняются, просто некорректно, для честности нужно и в раку брать «железные» инты.
В итоге, ты приходишь в тред, показываешь не идентичные бенчмарки, что результирует в немного (довольно сильно) скрывающие правду замеры, а люди это даже принимают за чистую монету.
Скорость это известная проблема, которая решается, но всё далеко не так драматично и печально, как было раньше.
Не профайлишь - не делай допущений, потому что они будут основываться на субъективной картине мира, которая может устареть, быть неполной, предвзятой whatever.
В итоге, ты приходишь в тред, показываешь не идентичные бенчмарки, что результирует в немного (довольно сильно) скрывающие правду замеры, а люди это даже принимают за чистую монету.
Я просто наблюдаю, что что-то происходит.
Попробуй вот такую процедуру, с таким не смухлевать:
sub stub() {
say 'stub';
}
$ time ./looping_lots.pl >/dev/null
real 0m18,280s
user 0m18,208s
sys 0m0,061s
$ time ./looping_lots.raku >/dev/null
real 4m30,129s
user 4m30,030s
sys 0m0,168s
Я предполагаю, что принципиальных отличий в реализации say типа flush’а по завершении, нет.
Попробуй вот такую процедуру, с таким не смухлевать:
Какой мухлёжь, профайлер открой и глянь что происходит. D:
Странно видеть в технической беседе гадания.
say ‘stub’
И тут мы получаем пенальти за grapheme-level юникод (которого толком ни у кого нет кроме раку), за диспатч say, за динамические переменные связанные с IO… Ждём, когда это всё сделают быстрее, здесь не могу не согласиться. Но это тоже не эквивалентный код, не стоит вводить в заблуждение. Фокус в том, что это два разных языка с разным набором фич, один из них гораздо более динамичный и имеет больше фич, при том что один оптимизировался лет 20-30, а второй - 2-3.
Да, здесь может быть контраргумент «Я просто программер, зачем мне все заумные фичи, я хочу всё и быстро и сейчас, вон как у языка другого-то, ну и что что он делает гораздо меньше работы в том же коде», но, мм. Не знаю. На мой взгляд, когда выходишь за пределы пятистрочников с циклами и принтами, начинается более интересная картина и фичи, которые облегчают написание, начинают рулить. Ну или кому как, вкусовщина и TimToady.
А так да, все хотят и фич и скорости и стабильности и батареек и желательно одновременно и всего побольше и мороженое, я тоже хочу.
Но это тоже не эквивалентный код, не стоит вводить в заблуждение.
Ладно… тогда, раз я заговорил о flush…
sub stub :prototype() {
STDERR->flush();
}
sub stub() {
$*ERR.flush();
}
Как у сего кода с эквивалентностью? Потому что разрыв сохраняется.
$ time ./looping_lots.pl
real 0m48,083s
user 0m48,020s
sys 0m0,040s
$ time ./looping_lots.raku
real 5m49,364s
user 5m27,473s
sys 0m21,818s
Фокус в том, что это два разных языка с разным набором фич, один из них гораздо более динамичный и имеет больше фич, при том что один оптимизировался лет 20-30, а второй - 2-3.
Я извиняюсь, ты точно настоящий сварщик, который знает, что такое $*ERR и как он работает?
Если верить документации, то это file handle для stderr.
Тонкостей я не знаю, увы.
Похоже, у меня в принципе не получится найти такой кусок кода, где не будет каких-нибудь подвохов, которые всё как бы меняют.
При этом эмпирическая закономерность «меньше фич @ меньше операций происходит в фоне @ проще железке» сохраняется с теми, кто быстрый и кто нет.
А как эта эмпирическая закономерность справляется с PHP 5.6 → PHP 7.4?
#!/usr/bin/env php
<?php
function stub()
{
fflush(STDERR);
}
for ($i = 0; $i < 10000; ++$i) {
for ($j = 0; $j < 10000; ++$j) {
stub();
}
}
$ time ./looping_lots.php
real 0m6,545s
user 0m6,535s
sys 0m0,004s
Или можно с JavaScript. SpiderMonkey тоже малофичный?
Похоже, у меня в принципе не получится найти такой кусок кода, где не будет каких-нибудь подвохов, которые всё как бы меняют.
А как ты хотел с языком, у которого фич выше крыши, части из которых толком нигде нет? Естественно под капотом там будет другая малина. С оптимизацией ряда вещей вообще толком нигде не сталкивались, только придумывать и впиливать. Это не означает, что тормоза навеки вечные, только означает, что сравнения должны быть более-менее честные. Но если хочешь «бенчмарков», попробуй выше приведённый:
class Point {
has $.x;
has $.y;
}
my $total = 0;
for ^1_000_000 {
my $p = Point.new(x => 2, y => 3);
$total = $total + $p.x+ $p.y;
}
say $total;
или такое:
my $fh = open "longfile"; # на миллион строк юникода
my $chars = 0;
for $fh.lines {
$chars = $chars + .chars
}
$fh.close;
say $chars;
или такое:
sub gcd(int $a is copy, int $b is copy) {
while $b != 0 {
my int $t = $b;
$b = $a % $b;
$a = $t;
}
$a
}
for ^2_000_000 {
die "oops" unless gcd(40, 30) == 10;
}
Я не уверен, о чём идёт разговор. Ты показал два скрипта, которые имеют разные свойства и отметил на разницу в скорости. Я чуть подправил один из них, чтобы быть ближе к первому, и разница нивелировалась. Вместо того, чтобы отметить это про себя в духе «Ага, значит ситуация несколько иная, интересно, если меня эта штука заинтересовала, возможно стоит узнать о ней побольше, а если я таким не интересуюсь, то пройти мимо», ты начал спекулировать «Я думаю, я предполагаю, сомневаюсь, деталей я не знаю» вместо того, чтобы копнуть в сорцы или хотя бы запрофайлить. Это очень странно для технической беседы… Но не суть.
Какой именно тезис ты хочешь показать? То, что ты ждёшь, пока скрипт будет выполняться быстрее? Уже было показано, что дождался. То, что некоторые вещи ещё не оптимизировали и они тормозят? Так это и так понятно, с этим никто не спорит. Или о чём речь, предметно?
какого код стайл придерживаться или о чем нужно помнить или правило большого пальца для того чтобы писать эффективный код? если всегда и во всех ситуациях нужно вникать это грусть-печаль-тоска-беда. особенно с учетом того что сегодня это ужас как медленно а завтра офигеть как быстро. да, это плохо. внезапно, да? сегодня мне нужно ускорять и хачить и я приобрел вредную привычку, а завтра хачить не нужно и без хака все даже лучше, но привычка уже есть.
изложил мысль как сумел, на коленке, надеюсь на понимание.
Я чуть подправил один из них, чтобы быть ближе к первому, и разница нивелировалась.
С моей точки зрения, ты дал интерпретатору возможность просто проигнорировать код.
После чего я решил доработать скрипты, чтобы они делали какую-нибудь номинальную работу более честно. И разница вернулась.
для технической беседы
Это Talks %).
Какой именно тезис ты хочешь показать? То, что ты ждёшь, пока скрипт будет выполняться быстрее? Уже было показано, что дождался.
Именно так. И нет, не дождался.
На замечание, что вызов $*ERR имеет свою цену, кстати, можно довольно нехитро ответить:
#!/usr/bin/env perl
use v5.12;
use warnings;
use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);
sub main :prototype() {
my $init_time = clock_gettime(CLOCK_MONOTONIC);
my $file = *STDERR;
for (my $i = 0; $i < 10_000; ++$i) {
for (my $j = 0; $j < 10_000; ++$j) {
$file->flush();
}
}
my $now_time = clock_gettime(CLOCK_MONOTONIC);
say STDERR sprintf("%.3fs", $now_time - $init_time);
}
main();
#!/usr/bin/env rakudo
use v6;
sub MAIN() {
my $file := $*ERR;
loop (my int $i = 0; $i < 10_000; ++$i) {
loop (my int $j = 0; $j < 10_000; ++$j) {
$file.flush();
}
}
note sprintf("%.3fs", now - INIT now);
}
С моей точки зрения, ты дал интерпретатору возможность просто проигнорировать код.
Наши точки зрения ничего не стоят, карта - это не территория. В профайлере можно посмотреть, что ничего не было проигнорировано. Я даже написал почему - return это не обычный ret обратно на следующую инструкцию вызывающего, а более динамичная штука. Реальный мир - это реальный мир, а не наши представления о том, что проигнорировалось.
И нет, не дождался.
Падажжи, это нужно перепроверить… Сейчас, вернусь к исходному примеру, который ты привёл…
Executed in 6.04 secs fish external
Executed in 1.12 secs fish external
По моему, это не просто приблизился, а даже немножко обогнал. D: Вызов есть? Есть. Железные инты есть? Есть. В чём проблема?
Если твой изначальный бенчмарк всё-таки приблизился, то ты не можешь показывать другие и говорить, мол, что не приблизился. Так и скажи: «Ок, с этим бенчмарком действительно результаты удовлетворительные, но вот здесь и вот (показываешь другие) здесь ещё стоит поработать».
Иначе это странный ход. Это как, не знаю. К примеру, ты говоришь, что из яблок нельзя жать сок. Дают соковыжималку, которая жмёт из яблок. Вместо того, чтобы продолжить «Ок, из яблок вы смогли, а можете из апельсинов теперь?», ты пишешь «Вы не можете из апельсинов, поэтому яблоки не засчитываются».
код
А вот это я сохраню, спасибо, буду тыкать этим кодом людям в глаза.
В профайлере можно посмотреть, что ничего не было проигнорировано. Я даже написал почему - return это не обычный ret обратно на следующую инструкцию вызывающего, а более динамичная штука. Реальный мир - это реальный мир, а не наши представления о том, что проигнорировалось.
Я это признал. И тогда я решил, что этот код не соответствует моему желанию иметь внутри циклов одинаковый номинальный код, который нельзя выоптимизировать, в обоих скриптах. Потому сразу пошёл искать альтернативу.
По моему, это не просто приблизился, а даже немножко обогнал. D: Вызов есть? Есть. Железные инты есть? Есть. В чём проблема?
Почему оно быстрее, когда как добавление внутрь любого кода меняет ситуацию кардинально?
Что за процессы приводят к такому результату?
Поэтому я отнёсся скептически к твоим результатам. Странно не соотносится.
Я так понимаю, суть вопроса примерно «Я не хочу писать на подмножестве, которое типа нормальное, хочу чтобы всё было нормальным».
Ответ на вопрос: «никак». В смысле, нет таких гайдлайнов или чего-то такого, точнее… Как писать более эффективный код - есть, конечно, приёмы, они есть в любом языке, я думаю (отсюда все эти effective C++, страницы об оптимизации кода на хаскелях и всё такое, но никто же не говорит, что всегда и во всех ситуациях нужно вникать и хачить в $langname).
Проблема в том, что здесь несколько искусственная подмена понятий, потому что существует ложь, большая ложь, очень большая ложь, обещания политиков и бенчмарки, где миллион раз что-то делают, а потом это ЭКСТРАПОЛИРУЮТ (обязательный xkcd про экстраполяцию) на любые программы на этом языке. В тех сферах, где ты можешь писать на raku удобненько: быстрое прототипирование, прототипирование многопоточного кода, клей-скриптуха, вебня какая-нибудь, совершенно другой код, согласись, и требования к нему другие.
Поэтому пишешь так, как хочется, и не паришься. Если не хватает скорости (только тогда) - профайлишь и смотришь, что там не так, что-то правишь, спрашиваешь у людей. Преждевременные оптимизации в пользовательском коде зло. А понимание о том, как оно работает внутри, всё равно рано или поздно будет полезным, если пишешь что-то интересное/нетривиальное, это так в любом языке. Хотя скорее всего у меня искажена картина, т.к. на $dayjob пишу в основном инструментарий для разных языков и приходится видеть some shit.