Processamento de arquivos grandes através de tubos bash, buffer?

6

Eu preciso usar um comando como o seguinte:

$ cat large.input.file | process.py > large.output.file

O problema é que, como isso acontece, o disco rígido não terá dificuldade em ler o arquivo de entrada e gravar o arquivo de saída?

Existe uma maneira de dizer ao bash para usar um grande buffer de memória ao fazer esse tipo de pipe?

    
por sanity 04.09.2009 / 23:34

7 respostas

4

Não se preocupe. O sistema operacional fará o buffer para você, e geralmente é muito bom nisso.

Isso sendo dito: Se você pode alterar o process.py, você pode implementar seu próprio buffering. Se você não pode mudar o process.py você pode escrever seu próprio buffer.py e usá-lo assim.

$ cat large.input.file | buffer.py | process.py | buffer.py > large.output.file

Provavelmente, muito mais fácil seria ler e escrever a partir de um disco RAM .

    
por 04.09.2009 / 23:38
8

O SO armazenará em buffer a saída para uma certa quantia, mas ainda pode haver muita movimentação da cabeça se os arquivos de entrada e saída estiverem na mesma unidade, a menos que seu process.py faça algum buffer próprio.

Você pode substituir cat no seu exemplo por visualizador de canais (pv) (disponível na maioria dos repositórios padrão e facilmente cumprido se não estiver no repo da sua distribuição) que permite que você defina o buffer para mais (com as opções -B / --buffer-bytes ) e exibe uma barra de progresso (a menos que você peça que não) que poderia seja muito útil para uma operação longa se seu process.py não exibir suas próprias informações de progresso. Para passar dados de um local em uma unidade para outro local na mesma unidade, isso pode fazer uma grande diferença, a menos que o processo geral seja principalmente vinculado à CPU, em vez de vinculado à E / S.

Então, para um buffer de 1Mb, você pode fazer:

pv -B 1m large.input.file | process.py > large.output.file

Eu uso pv o tempo todo para esse tipo de coisa, embora principalmente para o indicador de progresso mais do que o tamanho do buffer ajustável.

Outra opção é usar o mais "padrão" (padrão em termos de estar geralmente disponível por padrão, seu formato de linha de comando é um pouco diferente dos comandos mais comuns) dd , embora isso não tenha o recurso de barra de progresso :

dd if=large.input.file bs=1048576 | process.py > large.output.file

Editar: ps. Os pingentes podem apontar que cat não é necessário em seu exemplo, pois o seguinte também funcionará muito bem e será um pouco mais eficiente:

process.py < large.input.file > large.output.file

Algumas pessoas referem-se à remoção de chamadas não aceitas para cat como "demogificação", e essas pessoas provavelmente não devem ser incentivadas ...

    
por 05.09.2009 / 00:38
5

Não há uma antiga ferramenta unix chamada "buffer"? Não que isso seja necessário com as técnicas atuais de armazenamento em cache - mas está lá.

    
por 04.09.2009 / 23:49
3

Eu acredito que o problema que o usuário está aludindo é como o Input / Output geralmente funciona no mundo UNIX / Linux. Cada processo UNIX / Linux pode basicamente ter apenas uma operação de E / S pendente de cada vez. Assim, no caso do comando cat no exemplo, o comando cat primeiro lê alguns dados, espera que ele seja concluído, grava os dados e aguarda que sejam concluídos antes de continuar. Não há E / S simultânea em um processo, portanto, o buffer é usado apenas entre as leituras e as gravações para simplesmente manter temporariamente alguns dados.

Para acelerar as coisas, a entrada e a saída podem ser divididas em dois processos diferentes: um processo de leitura e um processo de gravação, e muita memória compartilhada usada como buffer entre os dois processos. Isso resulta na E / S simultânea que se deseja e pode acelerar o processo de transferência de arquivos.

O buffer do programa de utiilty, indicado por um usuário, implementa este método concorrente que descrevi. Eu usei o programa de buffer com um buffer de memória compartilhada bastante grande ao fazer a interface com uma unidade de fita para backups. Isso resultou em uma redução de cerca de 20% no tempo de transferência do relógio de parede.

Usar o programa de buffer como um substituto para o comando 'cat' pode resultar em algumas melhorias definidas ... dependendo.

Aproveite!

    
por 05.09.2009 / 01:46
2

Tente usar este pequeno programa do Python 2 que acabei de montar:

#! /usr/bin/python2
# This executable path is Gentoo-specific, you might need to change it yourself

import sys;

if sys.argv[1].endswith('K'):
   bytestoread = int(sys.argv[1].translate(None, 'K')) * 1024;
elif sys.argv[1].endswith('M'):
   bytestoread = int(sys.argv[1].translate(None, 'M')) * 1024 * 1024;
elif sys.argv[1].endswith('G'):
   bytestoread = int(sys.argv[1].translate(None, 'G')) * 1024 * 1024 * 1024;

while True:
   buffer = sys.stdin.read(bytestoread);
   if buffer == '':
      exit();
   sys.stdout.write(buffer);
   buffer = None;   # This one is for making sure the read buffer will get destroyed, otherwise we could bring our system to a halt if we have 8 GB of RAM, request a 5 GB buffer, and it ends up eating 10 GB of memory.

Para usar este arquivo, chame assim:

cat large.input.file | process.py | buffer.py 2G > large.output.file

Você pode usar 2K para especificar 2 kilobytes, 2M para 2 megabytes, 2G para 2 gigabytes, se desejar, adicione 2T para 2 terabytes de buffer: 3

Eu recebo esse problema o tempo todo ao compactar uma imagem de máquina virtual com pigz -1 , porque isso torna a compactação tão incrivelmente rápida que o disco começa a ler e a escrever simultaneamente e o processo é interrompido quando a cabeça do disco começa a zunir entre os arquivos de entrada e saída. Então, o que fiz foi criar este pequeno programa que lê um gigantesco bloco de dados da entrada padrão, grava-o na saída padrão e se repete. Quando a leitura retorna uma string em branco, é porque nenhuma entrada mais padrão foi recebida e o script é concluído.

    
por 20.05.2014 / 21:56
0

Ele será armazenado de forma inteligente, mas não há uma boa maneira de ajustar o quanto isso é necessário.

Você poderia escrever um programa intermediário que faria o cache que você quer e ler a partir da entrada.

    
por 04.09.2009 / 23:37
-1

Seu sistema operacional fará todos os tipos de armazenamento em cache nos arquivos antes que eles sejam gravados no disco rígido, e também fará o armazenamento em cache no arquivo que está sendo lido (geralmente lendo antecipadamente, se possível). Deixe o sistema operacional fazer o armazenamento em buffer e o armazenamento em cache.

Até que você possa provar o uso de testes e perfis de que o disco rígido é o fator limitante da equação, é melhor deixá-lo sozinho.

Se você puder alterar o process.py, você pode, em vez de ler / escrever com pipes, ler / escrever diretamente e usar arquivos de buffer e / ou memmap, o que ajudaria a remover parte do carregamento do sistema.

    
por 04.09.2009 / 23:40

Tags