Raku: есть ли СУПЕР быстрый способ превратить массив в строку без пробелов, разделяющих элементы? - PullRequest
8 голосов
/ 21 февраля 2020

Мне нужно преобразовать тысячи строк двоичных байтов, каждая длиной около мегабайта, в строки AS C. Это то, что я делал, и кажется слишком медленным:

sub fileToCorrectUTF8Str ($fileName) { # binary file
    my $finalString = "";
    my $fileBuf = slurp($fileName, :bin);    
    for @$fileBuf { $finalString = $finalString ~ $_.chr; };    
    return $finalString;
}

~ @ b превращает @b в строку со всеми элементами, разделенными пробелом, но это не то, что я хочу. Если @b = ; ~ @ b - это "ab c d"; но я просто хочу "abcd", и я хочу сделать это действительно быстро.

Итак, как лучше? Я не могу использовать гипер для параллелизма, потому что последняя строка строится последовательно. Или я могу?

1 Ответ

10 голосов
/ 21 февраля 2020

TL; DR На старом ракудо .decode примерно в 100 раз быстрее.

В более длинной форме, соответствующей вашему коду:

sub fileToCorrectUTF8Str ($fileName) { # binary file
  slurp($fileName, :bin).decode
}

Замечания по производительности

Во-первых, вот что я написал для тестирования:

# Create million and 1 bytes long file:
spurt 'foo', "1234\n6789\n" x 1e5 ~ 'Z', :bin;

# (`say` the last character to check work is done)
say .decode.substr(1e6) with slurp 'foo', :bin;

# fileToCorrectUTF8Str 'foo' );

say now - INIT now;

На Rocudo 2018.12 TIO.run вышеупомянутый .decode весит примерно .05 секунд на миллион байтовый файл вместо 5 секунд для вашего решения.

Конечно, вы можете / должны протестировать свою систему и / или использовать более поздние версии rakudo. Я ожидаю, что разница останется в том же порядке, но абсолютное время заметно улучшится с течением времени. [1]

Почему скорость в 100 раз выше?

Ну, во-первых, @ на Buf / Blob явно вынуждает raku просматривать прежний отдельный элемент ( a буфер) как множественное число (список элементов, также известный как несколько элементов s ). Это означает высокоуровневую итерацию, которая для буфера из миллиона элементов немедленно представляет собой миллион высокоуровневых итераций / операций вместо просто одной высокоуровневой операции.

Second, использование .decode не только позволяет избежать итерации, но и вызывает относительно медленный вызов метода накладных расходов один раз на файл, тогда как при итерации потенциально может быть миллион .chr вызовов на файл. Вызовы методов (по крайней мере, семантически) с поздней привязкой , что в принципе в принципе относительно дорого по сравнению, например, с вызовом sub вместо метода (подводные лодки, как правило, с ранним ограничением ).

Все это говорит:

  • Помните Предостережение Пусто [1] . Например, стандартные классы rakudo генерируют кеши методов, и вполне вероятно, что компилятор в любом случае просто вставляет метод в строку, поэтому возможно, что издержки для аспекта вызова метода незначительны.

  • См. Также Страница do c Performance , особенно Использовать существующий высокопроизводительный код .

Является ли сообщение об ошибке Buf.Str LTA ?

Обновление См. Комментарий Liz ++.

Если вы попытаетесь использовать .Str для Buf или Blob (или эквивалент, например, используя префикс ~, вы получите исключение. В настоящее время сообщение:

Cannot use a Buf as a string, but you called the Str method on it

do c для .Str на Buf / Blob в настоящее время говорит:

Чтобы преобразовать в Str, вам нужно использовать .decode.

Возможно, LTA, что сообщение об ошибке не предлагает то же самое.

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

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

Например, теперь есть SO, охватывающий эту проблему с сообщением об ошибке, так что Google скорее всего, получить один здесь. Использование этого может быть более подходящим путем, чем изменение сообщения об ошибке. Или это не так. Изменение было бы легко ...

Пожалуйста, рассмотрите возможность комментирования ниже и / или поиска существующих rakudo проблемы , чтобы увидеть, рассматривается ли улучшение сообщения об ошибке Buf.Str и / или вы wi sh чтобы открыть вопрос, чтобы предложить его изменить. Каждый сдвинутый камень - это, по крайней мере, большое упражнение, и, по мере того, как наши коллективные усилия становятся все более мудрыми, мы совершенствуем (на наш взгляд) гору .

Сноски

[1] Как гласит хорошо известная латинская поговорка Caveat Empty , как абсолютная, так и относительная производительность любой конкретной функции raku и, в более общем смысле, любого конкретного кода, всегда зависит от изменчивость, обусловленная такими факторами, как возможности системы, ее загрузка во время выполнения кода и любая оптимизация, выполняемая компилятором. Так, например, если ваша система «пуста», то ваш код может работать быстрее. Или, в качестве другого примера, если вы подождете год или три, чтобы компилятор стал быстрее, улучшения производительности rakudo продолжают выглядеть многообещающе .

...