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 / 501828
Accepted
dessert
dessert
Asked: 2019-02-21 03:32:16 +0800 CST2019-02-21 03:32:16 +0800 CST 2019-02-21 03:32:16 +0800 CST

Por que abrir um arquivo é mais rápido do que ler o conteúdo da variável?

  • 772

Em um bashscript, preciso de vários valores de /proc/arquivos. Até agora eu tenho dezenas de linhas grepping os arquivos diretamente assim:

grep -oP '^MemFree: *\K[0-9]+' /proc/meminfo

Em um esforço para tornar isso mais eficiente, salvei o conteúdo do arquivo em uma variável e fiz isso:

a=$(</proc/meminfo)
echo "$a" | grep -oP '^MemFree: *\K[0-9]+'

Em vez de abrir o arquivo várias vezes, isso deve abri-lo apenas uma vez e grep o conteúdo da variável, que eu assumi que seria mais rápido - mas na verdade é mais lento:

bash 4.4.19 $ time for i in {1..1000};do grep ^MemFree /proc/meminfo;done >/dev/null
real    0m0.803s
user    0m0.619s
sys     0m0.232s
bash 4.4.19 $ a=$(</proc/meminfo)
bash 4.4.19 $ time for i in {1..1000};do echo "$a"|grep ^MemFree; done >/dev/null
real    0m1.182s
user    0m1.425s
sys     0m0.506s

O mesmo vale para dashe zsh. Suspeitei do estado especial dos /proc/arquivos como motivo, mas quando copio o conteúdo de /proc/meminfoum arquivo regular e uso que os resultados são os mesmos:

bash 4.4.19 $ cat </proc/meminfo >meminfo
bash 4.4.19 $ time for i in $(seq 1 1000);do grep ^MemFree meminfo; done >/dev/null
real    0m0.790s
user    0m0.608s
sys     0m0.227s

Usar uma string here para salvar o pipe o torna um pouco mais rápido, mas ainda não tão rápido quanto com os arquivos:

bash 4.4.19 $ time for i in $(seq 1 1000);do <<<"$a" grep ^MemFree; done >/dev/null
real    0m0.977s
user    0m0.758s
sys     0m0.268s

Por que abrir um arquivo é mais rápido do que ler o mesmo conteúdo de uma variável?

bash shell-script
  • 3 3 respostas
  • 5062 Views

3 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2019-02-21T03:59:54+08:002019-02-21T03:59:54+08:00

    Aqui, não se trata de abrir um arquivo versus ler o conteúdo de uma variável, mas sim de bifurcar um processo extra ou não.

    grep -oP '^MemFree: *\K[0-9]+' /proc/meminfobifurca um processo que executa grepque abre /proc/meminfo(um arquivo virtual, na memória, sem E/S de disco envolvido) o lê e corresponde ao regexp.

    A parte mais cara disso é bifurcar o processo e carregar o utilitário grep e suas dependências de biblioteca, fazer a vinculação dinâmica, abrir o banco de dados locale, dezenas de arquivos que estão no disco (mas provavelmente armazenados em cache na memória).

    A parte sobre leitura /proc/meminfoé insignificante em comparação, o kernel precisa de pouco tempo para gerar as informações e grepprecisa de pouco tempo para lê-las.

    Se você executar strace -cisso, verá que uma open()e uma read()chamadas de sistema usadas para ler /proc/meminfosão amendoins em comparação com tudo o que grepfaz para iniciar ( strace -cnão conta a bifurcação).

    Dentro:

    a=$(</proc/meminfo)
    

    Na maioria dos shells que suportam esse $(<...)operador ksh, o shell apenas abre o arquivo e lê seu conteúdo (e remove os caracteres de nova linha à direita). bashé diferente e muito menos eficiente, pois bifurca um processo para fazer essa leitura e passa os dados para o pai por meio de um pipe. Mas aqui, é feito uma vez, então não importa.

    Dentro:

    printf '%s\n' "$a" | grep '^MemFree'
    

    O shell precisa gerar dois processos, que estão sendo executados simultaneamente, mas interagem entre si por meio de um pipe. Essa criação, desmontagem, escrita e leitura do cachimbo tem um custo pequeno. O custo muito maior é a geração de um processo extra. A programação dos processos também tem algum impacto.

    Você pode descobrir que usar o operador zsh o <<<torna um pouco mais rápido:

    grep '^MemFree' <<< "$a"
    

    No zsh e no bash, isso é feito escrevendo o conteúdo de $aum arquivo temporário, que é mais barato do que gerar um processo extra, mas provavelmente não lhe dará nenhum ganho comparado a obter os dados diretamente /proc/meminfo. Isso ainda é menos eficiente do que sua abordagem que copia /proc/meminfoem disco, pois a gravação do arquivo temporário é feita a cada iteração.

    dashnão suporta here-strings, mas seus heredocs são implementados com um pipe que não envolve a geração de um processo extra. Dentro:

     grep '^MemFree' << EOF
     $a
     EOF
    

    O shell cria um tubo, bifurca um processo. O filho executa grepcom seu stdin como a extremidade de leitura do pipe, e o pai grava o conteúdo na outra extremidade do pipe.

    Mas esse manuseio de pipe e sincronização de processo provavelmente ainda será mais caro do que apenas obter os dados diretamente /proc/meminfo.

    O conteúdo do /proc/meminfoé curto e não leva muito tempo para ser produzido. Se você deseja economizar alguns ciclos de CPU, deseja remover as partes caras: bifurcar processos e executar comandos externos.

    Curti:

    IFS= read -rd '' meminfo < /proc/meminfo
    memfree=${meminfo#*MemFree:}
    memfree=${memfree%%$'\n'*}
    memfree=${memfree#"${memfree%%[! ]*}"}
    

    Evite bashembora cuja correspondência de padrões seja muito ineficiente. Com zsh -o extendedglob, você pode encurtá-lo para:

    memfree=${${"$(</proc/meminfo)"##*MemFree: #}%%$'\n'*}
    

    Observe que ^é especial em muitos shells (Bourne, fish, rc, es e zsh com a opção extendedglob pelo menos), recomendo citá-lo. Observe também que echonão pode ser usado para produzir dados arbitrários (daí o meu uso printfacima).

    • 48
  2. Prvt_Yadav
    2019-02-21T04:03:44+08:002019-02-21T04:03:44+08:00

    No seu primeiro caso, você está apenas usando o utilitário grep e encontrando algo em file /proc/meminfo, /procé um sistema de arquivos virtual, então /proc/meminfoo arquivo está na memória e requer muito pouco tempo para buscar seu conteúdo.

    Mas no segundo caso, você está criando um pipe e passando a saída do primeiro comando para o segundo comando usando esse pipe, o que é caro.

    A diferença é por causa de /proc(porque está na memória) e pipe, veja o exemplo abaixo:

    time for i in {1..1000};do grep ^MemFree /proc/meminfo;done >/dev/null
    
    real    0m0.914s
    user    0m0.032s
    sys     0m0.148s
    
    
    cat /proc/meminfo > file
    time for i in {1..1000};do grep ^MemFree file;done >/dev/null
    
    real    0m0.938s
    user    0m0.032s
    sys     0m0.152s
    
    
    time for i in {1..1000};do echo "$a"|grep ^MemFree; done >/dev/null
    
    real    0m1.016s
    user    0m0.040s
    sys     0m0.232s
    
    • 6
  3. user232326
    2019-02-23T20:58:02+08:002019-02-23T20:58:02+08:00

    Você está chamando um comando externo em ambos os casos (grep). A chamada externa requer um subshell. Bifurcar essa concha é a causa fundamental do atraso. Ambos os casos são semelhantes, portanto: um atraso semelhante.

    Se você quiser ler o arquivo externo apenas uma vez e usá-lo (de uma variável) várias vezes, não saia do shell:

    meminfo=$(< /dev/meminfo)    
    time for i in {1..1000};do 
        [[ $meminfo =~ MemFree:\ *([0-9]*)\ *.B ]] 
        printf '%s\n' "${BASH_REMATCH[1]}"
    done
    

    O que leva apenas cerca de 0,1 segundo em vez do 1 segundo completo para a chamada grep.

    • 1

relate perguntas

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • MySQL Select com função IN () com array bash

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

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

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

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

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

    • 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

    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
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • 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
    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

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