Raku: existe uma maneira SUPER rápida de transformar uma matriz em uma string sem os espaços que separam os elementos?


8

Preciso converter milhares de cadeias de bytes binários, cada uma com cerca de um megabyte, em cadeias ASC. É o que tenho feito e parece muito lento:

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

~ @ b transforma @b em string com todos os elementos separados por espaço, mas não é isso que eu quero. Se @b = <abcd>; o ~ @ b é "abc d"; mas eu só quero "abcd" e quero fazer isso MUITO rápido.

Então, qual é a melhor maneira? Eu realmente não posso usar hiper para paralelismo porque a sequência final é construída seqüencialmente. Ou posso?

Respostas:


10

TL; DR Em um rakudo antigo, .decodeé cerca de 100 vezes mais rápido.

No formato mais longo para corresponder ao seu código:

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

Notas de desempenho

Primeiro, aqui está o que escrevi para o teste:

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

No rakudo do 2018.12TIO.run, o .decodepeso acima é de cerca de .05segundos por milhão de bytes, em vez de 5segundos para a sua solução.

É claro que você pode / deve testar em seu sistema e / ou usar versões posteriores do rakudo. Eu esperaria que a diferença permanecesse na mesma ordem, mas que os tempos absolutos melhorem acentuadamente à medida que os anos passam. [1]

Por que é 100X mais rápido?

Bem, em primeiro lugar, @em um Buf/ Blobexplicitamente forças Raku para ver o antigo item único ( um buffer) como um plural coisa (a lista de elementos aka múltipla artigo s ). Isso significa iteração de alto nível que, para um milhão de buffer de elemento, é imediatamente um milhão de iterações / operações de alto nível, em vez de apenas uma operação de alto nível.

Segundo, o uso .decodenão apenas evita a iteração, mas gera uma sobrecarga de chamada de método relativamente lenta uma vez por arquivo, enquanto na iteração há potencialmente um milhão de .chrchamadas por arquivo. As chamadas de método são (pelo menos semanticamente) com ligação tardia, o que é, em princípio, relativamente caro comparado a, por exemplo, chamar um sub em vez de um método (os subs são geralmente vinculados antecipadamente ).

Tudo isso disse:

  • Lembre-se de Advertência Vazia [1] . Por exemplo, as classes padrão do rakudo geram caches de método, e é plausível que o compilador apenas alinha o método de qualquer maneira, portanto é possível que haja uma sobrecarga insignificante para o aspecto de chamada de método.

  • Consulte também a página Desempenho do documento , especialmente Usar código de alto desempenho existente .

A Buf.Strmensagem de erro é LTA ?

Atualização Veja o comentário de Liz ++.

Se você tentar usar .Strum Bufou Blob(ou equivalente, como usar o ~prefixo nele), receberá uma exceção. Atualmente a mensagem é:

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

O documento para .Strem Buf/Blob atualmente diz:

Para converter para um Str, você precisa usar .decode.

É indiscutivelmente LTA que a mensagem de erro não sugere a mesma coisa.

Então, novamente, antes de decidir o que fazer sobre isso, se alguma coisa, é preciso considerar o que, e como, popular poderia aprender com qualquer coisa que der errado, incluindo sinais sobre o assunto, tais como mensagens de erro, e também o que e como eles fazem em atualmente, aprendemos e influenciamos nossas reações em direção à construção da cultura e infraestrutura certas .

Em particular, se as pessoas puderem se conectar facilmente entre uma mensagem de erro que vêem e a discussão on-line que a elabora, isso precisa ser levado em consideração e talvez incentivado e / ou facilitado.

Por exemplo, agora existe um SO que cobre esse problema com a mensagem de erro; portanto, é provável que o Google encontre alguém aqui. Se você se apoiar nesse caminho, pode ser um caminho mais apropriado do que alterar a mensagem de erro. Ou talvez não. A mudança seria fácil ...

Por favor, considere comentar abaixo e / ou pesquisar problemas de rakudo existentes para ver se a melhoria da Buf.Strmensagem de erro está sendo considerada e / ou se você deseja abrir uma questão para propor que ela seja alterada. Cada rocha movida é pelo menos um ótimo exercício e, à medida que nosso esforço coletivo se torna cada vez mais sábio, melhora (nossa visão) da montanha .

Notas de rodapé

[1] Como diz o famoso latim Caveat Empty , o desempenho absoluto e relativo de qualquer recurso raku específico e, geralmente, de qualquer código específico, está sempre sujeito a variações devido a fatores que incluem as capacidades do sistema, sua carga durante o tempo em que é executando o código e qualquer otimização feita pelo compilador. Assim, por exemplo, se seu sistema estiver "vazio", seu código poderá ser executado mais rapidamente. Ou, como outro exemplo, se você esperar um ano ou três para o compilador ficar mais rápido, os avanços no desempenho do rakudo continuam promissores .



2
Existem algumas maneiras pelas quais você pode otimizar ainda mais isso. slurpé apenas um invólucro IO::Path.slurp, neste caso, portanto, chamar .IO.slurptorna isso cerca de 2% mais rápido nos meus benchmarks. Se você digitar o arquivo com slurp :enc<latin1>, você terminará com um buffer de caracteres como faria com a codificação UTF-8 padrão, mas ignore as verificações para verificar se o arquivo slurped é ou não UTF-8 válido que você está executando ao decodificar. de qualquer maneira, para uma string UTF-8, o que também torna 10% mais rápido.
Kaiepi 22/02

Obrigado a todos pela ajuda !!! Com o .decode e outras pequenas alterações de código, passo cerca de 8 segundos para cada cadeia longa que tenho que processar. Obrigado !!!
lisprogtor 23/02

Olá, @lisprogtor A metáfora "raspar" significa "reduzir um número em uma quantidade muito pequena" . Qual foi o seu tempo antes de reduzi-lo para cerca de 8 segundos por corda longa? A redução é suficiente?
raiph 25/02

8 segundos é definitivamente melhor do que "raspar"! Obrigado !!!
lisprogtor 26/02
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.