LINUX.ORG.RU

Я всё жду, когда второй скрипт хотя бы приблизится к первому по скорости выполнения:

#!/usr/bin/env perl
use v5.12;
use warnings;

sub stub :prototype() {
    return;
}

sub main :prototype() {
    for (my $i = 0; $i < 10_000; ++$i) {
        for (my $j = 0; $j < 10_000; ++$j) {
            stub();
        }
    }
}
main();
#!/usr/bin/env rakudo
use v6;

sub stub() {
    return;
}

sub MAIN() {
    loop (my $i = 0; $i < 10_000; ++$i) {
        loop (my $j = 0; $j < 10_000; ++$j) {
            stub();
        }
    }
}
Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 1)
Ответ на: комментарий от scanner

Я даже полужирным шестёрку выделил, чтобы ты её не пропустил.
Всё напрасно.

Perl 6 != Perl.

Так в чём претензия-то? Ни @saahriktu, ни я ни разу не обмолвились, что вот, дескать, «Perl» был переименован в Raku.

Darth_Revan ★★★★★
()
Ответ на: комментарий от scanner

И чо? Новость конкретно про rakudo. И в стартовом сообщении я и напомнил что это такое. Что это компилятор вчерашнего Perl 6, который теперь переименовали в Raku.

При чём здесь «Perl переименовали???» и «Ну так, Perl-то не переименовали.» я вообще не представляю.

saahriktu ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

Бенчмарки? Где?
Просто запускаешь два идентичных по коду скрипта и смакуешь.
Если не смакуется, значит, починили.

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 1)
Ответ на: комментарий от atrus

Запустил оба скрипта, на Perl 5.30.1 и Rakudo 2020.02.
Вот:

$ time ./looping_lots.pl

real	0m9,837s
user	0m9,787s
sys	0m0,016s
$ time ./looping_lots.raku

real	1m22,547s
user	1m22,532s
sys	0m0,060s
Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 1)

Вышел rakudo...

На секунду подумал, что кто-то из лоровцев освободился... дальше увидел номер версии и хохотнул с себя.

xwicked ★★☆
()
Ответ на: комментарий от Darth_Revan

У тебя какой-то неправильный мёд…

➜  ~ cat perl.pl
#!/usr/bin/env perl
use v5.12;
use warnings;

sub stub :prototype() {
    return;
}

sub main :prototype() {
    for (my $i = 0; $i < 10_000; ++$i) {
        for (my $j = 0; $j < 10_000; ++$j) {
            stub();
        }
    }
}
main();
➜  ~ time perl perl.pl

________________________________________________________
Executed in    6.04 secs   fish           external 
   usr time    6.01 secs   59.00 micros    6.01 secs 
   sys time    0.01 secs  1028.00 micros    0.00 secs 

➜  ~ cat perl6.p6
#!/usr/bin/env rakudo
use v6;

sub stub() {}

sub MAIN() {
    loop (my int $i = 0; $i < 10_000; ++$i) {
        loop (my int $j = 0; $j < 10_000; ++$j) {
            stub;
        }
    }
}

➜  ~ time raku perl6.p6

________________________________________________________
Executed in    1.12 secs   fish           external 
   usr time  1150.99 millis   85.00 micros  1150.90 millis 
   sys time   31.71 millis  1044.00 micros   30.66 millis 

➜  ~ 

Я всё жду, когда второй скрипт хотя бы приблизится к первому по скорости выполнения

Ну, дождались!

Lilly
()
Последнее исправление: Lilly (всего исправлений: 1)

Этот релиз я срезал кривовато (теги: musl, нож в спину, боль), следующий будет гораздо интересней, т.к. подвезут отложенные специализации для вызовов.

Lilly
()
Ответ на: комментарий от atrus

Если следить за руками фокусника, то можно узнать, что это не идентичные скрипты. Если сделать их идентичнее, то выше замеры с удивительными цифрами.

Lilly
()
Ответ на: комментарий от gremlin_the_red

Пока что штука немного сомнительной нужности (на мой взгляд).

Релизы на онтопике и так есть, далее они опакечиваются под основные дистрибутивы, на макоси всё ставится, насколько я в курсе, а rakudo star когда-то был 1)сборником из компилятор + пакетник + «полезные» модули; 2)способом установить rakudo на оффтопике.

1 стало менее нужно, а оффтопик не нужно оффтопик не пользуется чудовищной популярностью у энтузиастов, использующих язык. Если уж идти в какую-то сторону, то в сторону упрощения, на мой взгляд, проще уж сделать отдельный инсталлятор под оффтопик и собирать так, чем иметь несколько циклов релизов и делать длинные объяснения в духе «Так-так, язык это такое, а это компилятор, а это виртуалка, а star это компилятор плюс модули, а ещё нет-нет постойте не уходите дослушайте».

Вот такая примерно ситуация.

Lilly
()
Ответ на: комментарий от Lilly

Если следить за руками фокусника, то можно узнать, что это не идентичные скрипты.

my int – правильное изменение, я не помню, чтобы оно влияло раньше, но результат налицо:

$ time ./a.raku

real	0m9,802s
user	0m9,835s
sys	0m0,041s

Но почто stub упростил? Его, наоборот, усложнять надо, чтобы хитрый интерпретатор не додумался его выоптимизировать вместе со всем циклом.
Что, похоже, и случается.

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 1)
Ответ на: комментарий от Darth_Revan

Но почто stub упростил? Его, наоборот, усложнять надо, чтобы хитрый интерпретатор не додумался его выоптимизировать вместе со всем циклом.

Во-первых, не интерпретатор, а компилятор в байткод в виртуалку с динамическими оптимизациями…

Не совсем так, это «ложные друзья переводчика», ну или «Если на любом языке писать как на фортране, будет фортран».

return в raku, в отличии от перла, это просто рутина, которая кидает control exception (которое можно красиво отловить и всё такое), и это всё не zero cost, а если ты хочешь просто ret, то тогда ты ничего и не делаешь. Сам вызов не убирается полностью, только JIT 100% вызовов, посмотреть это можно в профайлере.

Что же до int то тут опять таки: в raku честные big integers искоропки реализованные объектами (а ооп здесь полный фарш с мультиметодами, метаобъектным протоколом и всем остальным), поэтому сравнивать их с перловскими интами, которые переполняются, просто некорректно, для честности нужно и в раку брать «железные» инты.

В итоге, ты приходишь в тред, показываешь не идентичные бенчмарки, что результирует в немного (довольно сильно) скрывающие правду замеры, а люди это даже принимают за чистую монету.

Скорость это известная проблема, которая решается, но всё далеко не так драматично и печально, как было раньше.

А насчёт «хотя бы приблизится к скорости»: так бенчмарки это дело случая. Ждём, когда перл повторит https://6guts.wordpress.com/2018/10/06/speeding-up-object-creation/ (интересное, кстати, чтиво о внутренностях).

Lilly
()
Ответ на: комментарий от Darth_Revan

Что, похоже, и случается.

Не знаешь внутренностей - профайли.

Не профайлишь - не делай допущений, потому что они будут основываться на субъективной картине мира, которая может устареть, быть неполной, предвзятой whatever.

Lilly
()
Ответ на: комментарий от Lilly
➜  ~ raku
To exit type 'exit' or '^D'
> sub return($x) { say "Returning $x"; $x }
&return
> sub foo { return 42; }
&foo
> foo
Returning 42
> say foo
Returning 42
42
> 

Теперь нам нужен эквивалентный скрипт на перле.

Lilly
()
Ответ на: комментарий от Lilly

В итоге, ты приходишь в тред, показываешь не идентичные бенчмарки, что результирует в немного (довольно сильно) скрывающие правду замеры, а люди это даже принимают за чистую монету.

Я просто наблюдаю, что что-то происходит.

Попробуй вот такую процедуру, с таким не смухлевать:

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’а по завершении, нет.

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 2)
Ответ на: комментарий от Darth_Revan

Попробуй вот такую процедуру, с таким не смухлевать:

Какой мухлёжь, профайлер открой и глянь что происходит. D:

Странно видеть в технической беседе гадания.

say ‘stub’

И тут мы получаем пенальти за grapheme-level юникод (которого толком ни у кого нет кроме раку), за диспатч say, за динамические переменные связанные с IO… Ждём, когда это всё сделают быстрее, здесь не могу не согласиться. Но это тоже не эквивалентный код, не стоит вводить в заблуждение. Фокус в том, что это два разных языка с разным набором фич, один из них гораздо более динамичный и имеет больше фич, при том что один оптимизировался лет 20-30, а второй - 2-3.

Да, здесь может быть контраргумент «Я просто программер, зачем мне все заумные фичи, я хочу всё и быстро и сейчас, вон как у языка другого-то, ну и что что он делает гораздо меньше работы в том же коде», но, мм. Не знаю. На мой взгляд, когда выходишь за пределы пятистрочников с циклами и принтами, начинается более интересная картина и фичи, которые облегчают написание, начинают рулить. Ну или кому как, вкусовщина и TimToady.

А так да, все хотят и фич и скорости и стабильности и батареек и желательно одновременно и всего побольше и мороженое, я тоже хочу.

Lilly
()
Ответ на: комментарий от Lilly

Но это тоже не эквивалентный код, не стоит вводить в заблуждение.

Ладно… тогда, раз я заговорил о 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.

Фокус в том, что Perl5 тут тоже не быстрый %).

Darth_Revan ★★★★★
()
Ответ на: комментарий от Darth_Revan

Я извиняюсь, ты точно настоящий сварщик, который знает, что такое $*ERR и как он работает?

Фокус в том, что Perl5 тут тоже не быстрый %)

При этом эмпирическая закономерность «меньше фич @ меньше операций происходит в фоне @ проще железке» сохраняется с теми, кто быстрый и кто нет.

Lilly
()
Последнее исправление: Lilly (всего исправлений: 1)
Ответ на: комментарий от Lilly

Я извиняюсь, ты точно настоящий сварщик, который знает, что такое $*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 тоже малофичный?

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 2)
Ответ на: комментарий от Darth_Revan

Похоже, у меня в принципе не получится найти такой кусок кода, где не будет каких-нибудь подвохов, которые всё как бы меняют.

А как ты хотел с языком, у которого фич выше крыши, части из которых толком нигде нет? Естественно под капотом там будет другая малина. С оптимизацией ряда вещей вообще толком нигде не сталкивались, только придумывать и впиливать. Это не означает, что тормоза навеки вечные, только означает, что сравнения должны быть более-менее честные. Но если хочешь «бенчмарков», попробуй выше приведённый:

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;
}

Много интересных примеров и объяснений, что куда, есть в https://www.youtube.com/watch?v=QNeu0wK92NE Я понимаю, что никто здесь по ссылкам не ходит, но всё же рекомендовал бы подумать об описанных штуках, ну или хотя бы полистать слайды (http://jnthn.net/papers/2019-perlcon-performance.pdf)

Если верить документации, то это file handle для stderr.

А ещё это переменная с динамической областью видимости…

А как эта эмпирическая закономерность справляется с PHP 5.6 → PHP 7.4?

По твоему, PHP умеет столько же, сколько перл? Не пользовался, поэтому не могу сказать, спрашиваю честно.

Lilly
()
Ответ на: комментарий от Lilly

А ещё это переменная с динамической областью видимости…

И это даёт такой колоссальный разрыв?
Я, честно говоря, сомневаюсь.

По твоему, PHP умеет столько же, сколько перл? Не пользовался, поэтому не могу сказать, спрашиваю честно.

Не знаю, но PHP не аскетичен. Что-нибудь типа Moose поверх изобрести вряд ли получится, впрочем.

Darth_Revan ★★★★★
()
Ответ на: комментарий от Darth_Revan

И это даёт такой колоссальный разрыв?

Я не уверен, о чём идёт разговор. Ты показал два скрипта, которые имеют разные свойства и отметил на разницу в скорости. Я чуть подправил один из них, чтобы быть ближе к первому, и разница нивелировалась. Вместо того, чтобы отметить это про себя в духе «Ага, значит ситуация несколько иная, интересно, если меня эта штука заинтересовала, возможно стоит узнать о ней побольше, а если я таким не интересуюсь, то пройти мимо», ты начал спекулировать «Я думаю, я предполагаю, сомневаюсь, деталей я не знаю» вместо того, чтобы копнуть в сорцы или хотя бы запрофайлить. Это очень странно для технической беседы… Но не суть.

Какой именно тезис ты хочешь показать? То, что ты ждёшь, пока скрипт будет выполняться быстрее? Уже было показано, что дождался. То, что некоторые вещи ещё не оптимизировали и они тормозят? Так это и так понятно, с этим никто не спорит. Или о чём речь, предметно?

Lilly
()
Ответ на: комментарий от Lilly

ну ок, я задам свой вопрос.

какого код стайл придерживаться или о чем нужно помнить или правило большого пальца для того чтобы писать эффективный код? если всегда и во всех ситуациях нужно вникать это грусть-печаль-тоска-беда. особенно с учетом того что сегодня это ужас как медленно а завтра офигеть как быстро. да, это плохо. внезапно, да? сегодня мне нужно ускорять и хачить и я приобрел вредную привычку, а завтра хачить не нужно и без хака все даже лучше, но привычка уже есть.

изложил мысль как сумел, на коленке, надеюсь на понимание.

olelookoe ★★★
()
Ответ на: комментарий от Lilly

Я чуть подправил один из них, чтобы быть ближе к первому, и разница нивелировалась.

С моей точки зрения, ты дал интерпретатору возможность просто проигнорировать код.
После чего я решил доработать скрипты, чтобы они делали какую-нибудь номинальную работу более честно. И разница вернулась.

для технической беседы

Это 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);
}
$ ./looping_lots.pl
21.570s
$ ./looping_lots.raku
117.365s
Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 1)
Ответ на: комментарий от Darth_Revan

С моей точки зрения, ты дал интерпретатору возможность просто проигнорировать код.

Наши точки зрения ничего не стоят, карта - это не территория. В профайлере можно посмотреть, что ничего не было проигнорировано. Я даже написал почему - return это не обычный ret обратно на следующую инструкцию вызывающего, а более динамичная штука. Реальный мир - это реальный мир, а не наши представления о том, что проигнорировалось.

И нет, не дождался.

Падажжи, это нужно перепроверить… Сейчас, вернусь к исходному примеру, который ты привёл…

Executed in 6.04 secs fish external

Executed in 1.12 secs fish external

По моему, это не просто приблизился, а даже немножко обогнал. D: Вызов есть? Есть. Железные инты есть? Есть. В чём проблема?

Если твой изначальный бенчмарк всё-таки приблизился, то ты не можешь показывать другие и говорить, мол, что не приблизился. Так и скажи: «Ок, с этим бенчмарком действительно результаты удовлетворительные, но вот здесь и вот (показываешь другие) здесь ещё стоит поработать».

Иначе это странный ход. Это как, не знаю. К примеру, ты говоришь, что из яблок нельзя жать сок. Дают соковыжималку, которая жмёт из яблок. Вместо того, чтобы продолжить «Ок, из яблок вы смогли, а можете из апельсинов теперь?», ты пишешь «Вы не можете из апельсинов, поэтому яблоки не засчитываются».

код

А вот это я сохраню, спасибо, буду тыкать этим кодом людям в глаза.

Lilly
()
Ответ на: комментарий от Lilly

В профайлере можно посмотреть, что ничего не было проигнорировано. Я даже написал почему - return это не обычный ret обратно на следующую инструкцию вызывающего, а более динамичная штука. Реальный мир - это реальный мир, а не наши представления о том, что проигнорировалось.

Я это признал. И тогда я решил, что этот код не соответствует моему желанию иметь внутри циклов одинаковый номинальный код, который нельзя выоптимизировать, в обоих скриптах. Потому сразу пошёл искать альтернативу.

По моему, это не просто приблизился, а даже немножко обогнал. D: Вызов есть? Есть. Железные инты есть? Есть. В чём проблема?

Почему оно быстрее, когда как добавление внутрь любого кода меняет ситуацию кардинально?
Что за процессы приводят к такому результату?

Поэтому я отнёсся скептически к твоим результатам. Странно не соотносится.

Darth_Revan ★★★★★
()
Последнее исправление: Darth_Revan (всего исправлений: 1)
Ответ на: комментарий от olelookoe

Так, отвечу по быстрому.

Я так понимаю, суть вопроса примерно «Я не хочу писать на подмножестве, которое типа нормальное, хочу чтобы всё было нормальным».

Ответ на вопрос: «никак». В смысле, нет таких гайдлайнов или чего-то такого, точнее… Как писать более эффективный код - есть, конечно, приёмы, они есть в любом языке, я думаю (отсюда все эти effective C++, страницы об оптимизации кода на хаскелях и всё такое, но никто же не говорит, что всегда и во всех ситуациях нужно вникать и хачить в $langname).

Проблема в том, что здесь несколько искусственная подмена понятий, потому что существует ложь, большая ложь, очень большая ложь, обещания политиков и бенчмарки, где миллион раз что-то делают, а потом это ЭКСТРАПОЛИРУЮТ (обязательный xkcd про экстраполяцию) на любые программы на этом языке. В тех сферах, где ты можешь писать на raku удобненько: быстрое прототипирование, прототипирование многопоточного кода, клей-скриптуха, вебня какая-нибудь, совершенно другой код, согласись, и требования к нему другие.

Поэтому пишешь так, как хочется, и не паришься. Если не хватает скорости (только тогда) - профайлишь и смотришь, что там не так, что-то правишь, спрашиваешь у людей. Преждевременные оптимизации в пользовательском коде зло. А понимание о том, как оно работает внутри, всё равно рано или поздно будет полезным, если пишешь что-то интересное/нетривиальное, это так в любом языке. Хотя скорее всего у меня искажена картина, т.к. на $dayjob пишу в основном инструментарий для разных языков и приходится видеть some shit.

Lilly
()
Ответ на: комментарий от Lilly

Поэтому пишешь так, как хочется, и не паришься.

так и делаю, просто подумал что, возможно, это не правильно и есть какой-нибудь гайд, о котором мне следовало бы знать.

а бенчи нет, бенчи меня мало беспокоят.

olelookoe ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.