AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 450877
Accepted
mas
mas
Asked: 2018-06-21 05:40:55 +0800 CST2018-06-21 05:40:55 +0800 CST 2018-06-21 05:40:55 +0800 CST

Como os pipelines limitam o uso de memória?

  • 772

Brian Kernighan explica neste vídeo a atração inicial do Bell Labs por pequenas linguagens/programas baseados em limitações de memória

Uma máquina grande teria 64 k-bytes - K, não M ou G - e isso significava que qualquer programa individual não poderia ser muito grande, e então havia uma tendência natural de escrever programas pequenos, e então o mecanismo de pipe, basicamente o redirecionamento de entrada e saída, tornou possível vincular um programa a outro.

Mas não entendo como isso pode limitar o uso de memória, considerando o fato de que os dados precisam ser armazenados na RAM para transmitir entre os programas.

Da Wikipédia :

Na maioria dos sistemas do tipo Unix, todos os processos de um pipeline são iniciados ao mesmo tempo [ênfase minha], com seus fluxos adequadamente conectados e gerenciados pelo agendador junto com todos os outros processos em execução na máquina. Um aspecto importante disso, separando os pipes Unix de outras implementações de pipe, é o conceito de buffer: por exemplo, um programa de envio pode produzir 5.000 bytes por segundo, e um programa de recebimento pode aceitar apenas 100 bytes por segundo, mas não dados são perdidos. Em vez disso, a saída do programa de envio é mantida no buffer. Quando o programa receptor estiver pronto para ler os dados, o próximo programa no pipeline fará a leitura do buffer. No Linux, o tamanho do buffer é de 65.536 bytes (64 KB). Um filtro de terceiros de código aberto chamado bfr está disponível para fornecer buffers maiores, se necessário.

Isso me confunde ainda mais, pois isso anula completamente o propósito de pequenos programas (embora eles sejam modulares até uma certa escala).

A única coisa que posso pensar como uma solução para minha primeira pergunta (as limitações de memória sendo problemáticas dependendo do tamanho dos dados) seria que grandes conjuntos de dados simplesmente não eram computados na época e os pipelines de problemas reais deveriam resolver era o quantidade de memória exigida pelos próprios programas. Mas dado o texto em negrito na citação da Wikipedia, até isso me confunde: como um programa não é implementado de cada vez.

Tudo isso faria muito sentido se os arquivos temporários fossem usados, mas é meu entendimento que os pipes não gravam no disco (a menos que a troca seja usada).

Exemplo:

sed 'simplesubstitution' file | sort | uniq > file2

Está claro para mim que sedestá lendo o arquivo e cuspindo-o linha por linha. Mas sort, como BK afirma no vídeo vinculado, é um ponto final, então todos os dados precisam ser lidos na memória (ou é?), então são passados ​​para uniq, o que (na minha opinião) seria um -programa linha por vez. Mas entre o primeiro e o segundo pipe, todos os dados têm que estar na memória, não?

pipe history
  • 3 3 respostas
  • 9115 Views

3 respostas

  • Voted
  1. Best Answer
    Stephen Kitt
    2018-06-21T05:46:24+08:002018-06-21T05:46:24+08:00

    Os dados não precisam ser armazenados na RAM. Pipes bloqueiam seus escritores se os leitores não estiverem lá ou não puderem acompanhar; no Linux (e na maioria das outras implementações, imagino) há algum buffer, mas isso não é necessário. Como mencionado por mtraceur e JdeBP (veja a resposta deste último), versões anteriores do Unix buffered pipes to disk, e foi assim que eles ajudaram a limitar o uso de memória: um pipeline de processamento poderia ser dividido em pequenos programas, cada um dos quais processaria alguns dados, dentro dos limites dos buffers de disco. Programas pequenos ocupam menos memória, e o uso de pipes significava que o processamento poderia ser serializado: o primeiro programa seria executado, preencheria seu buffer de saída, seria suspenso, então o segundo programa seria escalonado, processar o buffer, etc. de magnitude maior do que os primeiros sistemas Unix, e pode executar muitos tubos em paralelo; mas para grandes quantidades de dados, você ainda veria um efeito semelhante (e variantes desse tipo de técnica são usadas para processamento de “big data”).

    No seu exemplo,

    sed 'simplesubstitution' file | sort | uniq > file2
    

    sedlê os dados fileconforme necessário e depois os grava enquanto sortestiver pronto para lê-los; se sortnão estiver pronto, os blocos de gravação. Os dados de fato vivem na memória eventualmente, mas isso é específico para o sort, e sortestá preparado para lidar com quaisquer problemas (ele usará arquivos temporários se a quantidade de dados a ser classificada for muito grande).

    Você pode ver o comportamento de bloqueio executando

    strace seq 1000000 -1 1 | (sleep 120; sort -n)
    

    Isso produz uma quantidade razoável de dados e os canaliza para um processo que não está pronto para ler nada nos primeiros dois minutos. Você verá uma série de writeoperações passarem, mas muito rapidamente seqirá parar e esperar os dois minutos se passarem, bloqueados pelo kernel (a writechamada do sistema espera).

    • 52
  2. JdeBP
    2018-06-21T07:27:34+08:002018-06-21T07:27:34+08:00

    Mas não entendo como isso pode limitar o uso de memória, considerando o fato de que os dados precisam ser armazenados na RAM para transmitir entre os programas.

    Este é o seu erro fundamental. As primeiras versões do Unix não continham dados de pipe na RAM. Eles os armazenaram em disco. Pipes tinham i-nodes; em um dispositivo de disco que foi indicado como dispositivo de tubo . O administrador do sistema executou um programa chamado /etc/configpara especificar (entre outras coisas) qual volume em qual disco era o dispositivo de pipe, qual volume era o dispositivo raiz e qual era o dispositivo de despejo .

    A quantidade de dados pendentes foi limitada pelo fato de que apenas os blocos diretos do i-node no disco foram usados ​​para armazenamento. Esse mecanismo tornou o código mais simples, porque para a leitura de um pipe foi empregado o mesmo algoritmo usado para a leitura de um arquivo comum, com alguns ajustes causados ​​pelo fato de que os pipes não são pesquisáveis ​​e o buffer é circular.

    Esse mecanismo foi substituído por outros em meados da década de 1980. A SCO XENIX ganhou o "Sistema de Pipe de Alto Desempenho", que substituiu os i-nodes por buffers in-core. O 4BSD transformou tubos sem nome em pares de soquetes. A AT&T reimplementou os tubos usando o mecanismo STREAMS.

    E é claro que o sortprograma executou um tipo interno limitado de pedaços de entrada de 32KiB (ou qualquer quantidade menor de memória que pudesse alocar se 32KiB não estivesse disponível), gravando os resultados classificados em stmX??arquivos intermediários nos /usr/tmp/quais, em seguida, mesclava externamente para fornecer o resultado final. resultado.

    Leitura adicional

    • Steve D. Pate (1996). "Comunicação entre processos". UNIX Internals: Uma Abordagem Prática . Addison-Wesley. ISBN 9780201877212.
    • Maurice J. Bach (1987). "Chamadas de sistema para o sistema de arquivos". O Projeto do Sistema Operacional Unix . Prentice-Hall. ISBN 0132017571.
    • Steven V. Earhart (1986). " config(1M)". Manual do Programador Unix: 3. Facilidades de Administração do Sistema . Holt, Rinehart e Winston. ISBN 0030093139. pp. 23–28.
    • Abhijit Menon-Sen (2020-03-23). Como os pipes Unix são implementados? . toroid.org.
    • 36
  3. Damon
    2018-06-23T04:35:32+08:002018-06-23T04:35:32+08:00

    Você está parcialmente correto, mas apenas por acidente .

    No seu exemplo, todos os dados devem realmente ter sido lidos "entre" os pipes, mas não precisam estar residentes na memória (incluindo a memória virtual). As implementações usuais de sortpodem classificar conjuntos de dados que não cabem na RAM fazendo classificações parciais em arquivos temporários e mesclando. No entanto, é um fato que você não pode produzir uma sequência ordenada antes de ler cada elemento. Isso é bastante óbvio. Então, sim, sortsó pode começar a enviar para o segundo pipe depois de ler (e fazer o que for, possivelmente classificar parcialmente os arquivos temporários) tudo desde o primeiro. Mas não precisa necessariamente manter tudo na RAM.

    No entanto, isso não tem nada a ver com o funcionamento dos tubos. Pipes podem ser nomeados (tradicionalmente todos eles eram nomeados), o que significa nada mais e nada menos do que eles têm um local no sistema de arquivos, como arquivos. E isso é exatamente o que os pipes eram uma vez, arquivos (com gravações reunidas tanto quanto a disponibilidade de memória física permitiria, como uma otimização).

    Hoje em dia, pipes são um buffer de kernel pequeno e de tamanho finito para o qual os dados são copiados, pelo menos é o que acontece conceitualmente . Se o kernel puder ajudá-lo, as cópias são eliminadas usando truques de VM (por exemplo, o pipe de um arquivo geralmente apenas disponibiliza a mesma página para o outro processo ler, então é finalmente apenas uma operação de leitura, não duas cópias e não memória adicional do que já é usada pelo cache de buffer de qualquer maneira é necessária. Em algumas situações você pode obter 100% de cópia zero também. Ou algo muito próximo.

    Se os pipes são pequenos e de tamanho finito, como isso pode funcionar para qualquer quantidade de dados desconhecida (possivelmente grande)? É simples: quando nada mais cabe, a gravação bloqueia até que haja espaço novamente.

    A filosofia de muitos programas simples foi muito útil em uma época em que a memória era muito escassa. Porque, bem, você pode trabalhar em pequenos passos, um de cada vez. Hoje em dia, as vantagens são, além de alguma flexibilidade extra, ouso dizer, já não tão grandes.
    No entanto, pipes são implementados de forma muito eficiente (tinha que ser!), então também não há desvantagem, e é uma coisa estabelecida que está funcionando bem e que as pessoas estão acostumadas, então não há necessidade de mudar o paradigma.

    • 1

relate perguntas

  • escreva um histórico semelhante de shell script no console [fechado]

  • Passe o identificador para o pipeline stdin down

  • Como canalizar um comando bash e manter Ctrl + C funcionando?

  • Por que canalizar `mysql` para 'tail' altera o formato de saída?

  • ordem de substituição de processos `te` e `bash`

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve