Para um arquivo realmente grande como 1 GB, wc -l
é lento. Temos uma maneira mais rápida de calcular o número de novas linhas para um arquivo específico?
command-line
wc
prosti
fonte
fonte
0x0A
, a E / S é sem dúvida o gargalo.wc
de ter sobrecarga demais, tente implementar o seu próprioforeach byte in file: if byte == '\n': linecount++
. Se implementado em C ou assembler, acho que não ficará mais rápido, exceto talvez no espaço do kernel em um RTOS com maior prioridade (ou até use uma interrupção para isso - você simplesmente não pode fazer mais nada com o sistema. .. tudo bem, eu discordo ;-))time wc -l some_movie.avi
em um arquivo não armazenado em cache, resultando em5172672 some_movie.avi -- real 0m57.768s -- user 0m0.255s -- sys 0m0.863s
. O que basicamente prova que o @thrig está certo, a E / S prejudica seu desempenho nesse caso.time wc -l some_large_file_smaller_than_cache
duas vezes em rápida sucessão e veja a rapidez da segunda operação,time wc -l some_large_file_larger_than_cache
e veja como o tempo não muda entre as execuções. Para um arquivo de ~ 280 MB aqui, o tempo varia de 1,7 segundos a 0,2 segundos, mas para um arquivo de 2 GB são 14 segundos nas duas vezes./usr/bin/time wc -l <file>
diz? Qual é o seu hardware? É mais rápido se você executar o comando repetidamente? Nós realmente precisamos de mais informações;)Respostas:
Você pode tentar escrever em C:
Salvar em, por exemplo,
wcl.c
compilar, por exemplo, comgcc wcl.c -O2 -o wcl
e executar comIsso encontra novas linhas espalhadas em um arquivo de 1 GB no meu sistema em cerca de 370ms (execuções repetidas). (O aumento do tamanho do buffer aumenta um pouco o tempo, o que é esperado - o BUFSIZ deve estar próximo do ideal). Isso é muito comparável aos ~ 380ms que estou obtendo
wc -l
.Mmaping me proporciona um tempo melhor de cerca de 280ms , mas é claro que tem a limitação de ser limitado a arquivos reais (sem FIFOS, sem entrada de terminal etc.):
Eu criei meu arquivo de teste com:
e adicionou algumas linhas de teste com:
e um editor hexadecimal.
fonte
for
loop OpenMP ), para que algum progresso possa ser feito enquanto um thread estiver parado aguardando a entrada. Mas, por outro lado, isso pode dificultar o agendamento de E / S; portanto, tudo o que posso recomendar é experimentá-lo e medir!read()
versão pode se beneficiar da leitura antecipada.Você pode aprimorar a solução sugerida pelo @pskocik reduzindo o número de chamadas para
read
. Existem muitas chamadas para lerBUFSIZ
blocos de um arquivo de 1 GB. A abordagem usual para fazer isso é aumentando o tamanho do buffer:BUFSIZ
é 8192. No programa original, são 120 mil operações de leitura. Provavelmente, você pode pagar um buffer de entrada de 1Mb para reduzi-lo por um fator de 100.Ao comparar as várias abordagens, lembre-se de que alguns sistemas (como o Linux) usam a maior parte da memória não utilizada da sua máquina como cache de disco. Há um tempo (quase 20 anos atrás, mencionado nas vil Perguntas frequentes ), fiquei surpreendido com resultados inesperadamente bons de um algoritmo de paginação (não muito bom) que eu havia desenvolvido para lidar com condições de pouca memória em um editor de texto. Foi-me explicado que funcionava rápido porque o programa estava funcionando com os buffers de memória usados para ler o arquivo e que somente se o arquivo fosse relido ou gravado, haveria uma diferença na velocidade.
O mesmo se aplica a
mmap
(em outro caso ainda na minha lista de tarefas a incorporar em uma FAQ, um desenvolvedor relatou resultados muito bons em um cenário em que o cache do disco era o motivo real da melhoria). O desenvolvimento de benchmarks leva tempo e cuidado para analisar os motivos do bom (ou ruim) desempenho.Leitura adicional:
fonte
dd
buffers de 1 MB é mais lento que 8 KB. O valor padrão de 8 KB para o wc é realmente escolhido muito bem; ele estará próximo do ideal para uma grande variedade de sistemas.