O gato usa avaliação preguiçosa?

O gato usa avaliação preguiçosa?

Ao usar tubos, por exemplo

sudo cat /dev/sda | strings | less

Posso mover-me pelas linhas de strings do meu dispositivo sda. Mas o conteúdo do dispositivo sda está totalmente carregado e enviado para o fluxo de saída do cat? Ou as novas linhas são avaliadas sempre que um programa solicita saída de cat ? (ou seja, eu pressiono j no pager menor)

Responder1

Isso tem mais a ver com como lessfunciona do que com como catou stringsfunciona.

O catcomando apenas enviará os dados para sua saída padrão e será bloqueado sempre que o buffer do pipe entre ele e stringsestiver cheio e ninguém estiver lendo. catfaz um buffer mínimo por si só, e o buffer do pipe normalmente é pequeno.

Isto também é verdade para strings. Ele processará os dados cate bloqueará quando lessnão estiver lendo os dados que stringsproduz.

lessarmazenará sua entrada em buffer para permitir que você avance e retroceda nos dados exibidos. Quando você rolar para a próxima página, lessmais dados serão lidos stringsem seu buffer. Enquanto você não estiver avançando, acredito que lesslerá apenas uma quantidade limitada de dados (e, portanto, stringsserá catbloqueado enquanto você não estiver avançando).

Se você canalizar uma grande quantidade de dados para less, muita memória será usada para esse buffersevocê decide ler tudo até o fim com less.

Existe uma opção, -Bque limita a quantidade de memória usada para buffer a 64 kilobytes (ou o quanto você especificar com a -bopção). Limitar o tamanho do buffer dessa maneira impedirá que você role para trás mais do que pode ser armazenado no espaço do buffer especificado, mas também permitirá que você leia grandes quantidades de dados sem lessficar sem memória.

Veja também man lessno seu sistema.

Responder2

Os pipes têm espaço de buffer limitado e se um leitor de pipe (como lessno seu exemplo) não ler mais dados do pipe, o gravador será bloqueado após preencher o buffer. Isso afetará o stringscomando, que por sua vez bloqueará o catcomando depois que seu canal estiver cheio.

Naturalmente, o catcomando não pode ler todo o conteúdo do dispositivo sda na memória principal, portanto, se blocos que ainda não foram lidos por ele estiverem sendo alterados, catele verá o conteúdo alterado.

Responder3

Ambos cate strings, e a maioria dos utilitários semelhantes¹, leem um pouco da entrada por vez, processam-na e, em seguida, leem mais entradas e assim por diante. Então, no seu caso, catlê apenas o que lessé exibido, além de um pouco mais que está em trânsito.

Mais detalhadamente, a operação básica de caté:

  • Reserve alguns kilobytes de memória para usar como buffer.
  • Embora haja mais informações disponíveis:
    • Leia até N bytes de entrada no buffer. (Isso substitui os dados que foram gravados em um ciclo anterior.)
    • Grave o conteúdo do buffer na saída.

A operação de gravação é bloqueada até que haja um local para copiar a saída. Quando a saída de um pipe, o próprio pipe consome um pouco de memória no kernel, que é chamado debuffer de tubo. Quando estiver cheio, se cattentar gravar no canal, a tentativa de gravação será bloqueada até que haja espaço. Pode haver espaço no buffer do pipe quando o processo na extremidade de leitura do pipe lê alguns dados.

O stringsprograma funciona da mesma forma que o cat, exceto que não copia toda a entrada, apenas partes selecionadas.

O lessprograma funciona de maneira um pouco diferente: mantém tudo o que é lido na memória. Ele não recicla seu buffer, ele continua aumentando-o enquanto mais entradas continuam chegando. A parte de leitura é semelhante, entretanto, no sentido de que lesssó lê os dados quando necessário: ele só lê até a última linha que exibe , além de um pouco mais que lê antecipadamente, se disponível.

Então, quando você executa sudo cat /dev/sda | strings | less, o que foi lido /dev/sdaconsiste em:

  • Dados que lessjá foram exibidos (ou passados).
  • Até alguns kB de dados que lessforam lidos, mas ainda não exibidos.
  • Até alguns kB no buffer de pipe entre stringse less.
  • Até alguns kB na memória do arquivo strings.
  • Até alguns kB no buffer de pipe entre cate strings.
  • Até alguns kB na memória do arquivo cat.

Você pode observar quando cada programa lê e grava dados rastreando suas chamadas de sistema:

sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less

e observe os *.stracearquivos. Você também pode verificar quanto catfoi lido verificando o deslocamento do arquivo, por exemplo com lsof -p1234ou com head /proc/1234/fdinfo/0onde 1234está o ID do processo de cat.

¹ Entre os utilitários básicos de processamento de texto, a principal exceção é o sort, que não pode emitir nenhuma saída até que leia toda a entrada: pelo que sabe, a primeira linha da saída pode muito bem ser a última linha da entrada que alcança.

Responder4

Em alguns sistemas (por exemplo, MS-Dos) o pipe é implementado copiando a saída do primeiro comando para um arquivo e executando o segundo comando para ler esse arquivo. Unix não faz dessa maneira.

Nos Unixes é como uma linha de produção. Cada estágio funciona simultaneamente, lendo a entrada e produzindo a saída. Se o processo A produz mais rápido do que o processo B consome, então há um acúmulo de estoque entre os processos A e B. Quando isso é demais (½KiB a 4 KiB), o processo A é pausado. Quando não há estoque para B processar, B é pausado. Os processos são pausados ​​e retomados, para manter baixos os níveis de estoque.

O código desses programas não se importa com nada disso. Ele apenas lê a entrada e grava a saída. Se ele tentar ler, antes que os dados estejam disponíveis, ou tentar gravar antes que o próximo processo esteja pronto, o sistema operacional irá pausá-lo, até que esteja pronto.

Quando não há mais nada para ler (e nada mais está a caminho), o leitor obtém um fim de arquivo e sai. Isso, por sua vez, aciona um fim de arquivo no próximo processo.

informação relacionada