Qui, non si tratta di aprire un file contro la lettura di contenuti di una variabile , ma più su fork di un processo più o meno.
grep -oP '^MemFree: *\K[0-9]+' /proc/meminfo
esegue un fork che esegue un processo che si grep
apre /proc/meminfo
(un file virtuale, in memoria, nessun I / O del disco coinvolto) lo legge e corrisponde al regexp.
La parte più costosa in ciò è il fork del processo e il caricamento dell'utilità grep e delle sue dipendenze della libreria, il collegamento dinamico, l'apertura del database delle impostazioni locali, dozzine di file che sono sul disco (ma probabilmente memorizzati nella cache).
La parte relativa alla lettura /proc/meminfo
è insignificante in confronto, il kernel ha bisogno di poco tempo per generare le informazioni lì dentro e ha grep
bisogno di poco tempo per leggerle.
Se lo esegui strace -c
, vedrai che le chiamate di sistema uno open()
e uno read()
utilizzate per leggere /proc/meminfo
sono noccioline rispetto a tutto ciò che grep
fa per iniziare ( strace -c
non conta il fork).
Nel:
a=$(</proc/meminfo)
Nella maggior parte delle shell che supportano $(<...)
quell'operatore ksh, la shell apre semplicemente il file e legge il suo contenuto (e rimuove i caratteri di nuova riga finali). bash
è diverso e molto meno efficiente in quanto prevede un processo per eseguire tale lettura e passa i dati al genitore tramite una pipe. Ma qui, è fatto una volta, quindi non importa.
Nel:
printf '%s\n' "$a" | grep '^MemFree'
La shell deve generare due processi, che sono in esecuzione contemporaneamente ma interagiscono tra loro tramite una pipe. Quella creazione di pipe, lo smantellamento, la scrittura e la lettura da essa ha un costo limitato. Il costo molto maggiore è la generazione di un processo aggiuntivo. Anche la pianificazione dei processi ha un certo impatto.
Potresti scoprire che l'uso <<<
dell'operatore zsh lo rende leggermente più veloce:
grep '^MemFree' <<< "$a"
In zsh e bash, ciò avviene scrivendo il contenuto di $a
un file temporaneo, che è meno costoso rispetto alla generazione di un processo aggiuntivo, ma probabilmente non ti darà alcun guadagno rispetto al recupero immediato dei dati /proc/meminfo
. È ancora meno efficiente del tuo approccio che copia /proc/meminfo
su disco, poiché la scrittura del file temporaneo viene eseguita ad ogni iterazione.
dash
non supporta le stringhe qui, ma i suoi heredoc sono implementati con una pipe che non comporta la generazione di un processo aggiuntivo. Nel:
grep '^MemFree' << EOF
$a
EOF
La shell crea una pipe, crea un processo. Il bambino esegue grep
con il suo stdin come estremità di lettura della pipe e il genitore scrive il contenuto all'altra estremità della pipe.
Ma è probabile che la gestione dei tubi e la sincronizzazione dei processi siano ancora più costosi rispetto al semplice recupero dei dati /proc/meminfo
.
Il contenuto di /proc/meminfo
è breve e non richiede molto tempo per la produzione. Se si desidera salvare alcuni cicli della CPU, si desidera rimuovere le parti costose: processi di fork e comandi esterni.
Piace:
IFS= read -rd '' meminfo < /proc/meminfo
memfree=${meminfo#*MemFree:}
memfree=${memfree%%$'\n'*}
memfree=${memfree#"${memfree%%[! ]*}"}
Evita bash
però che il pattern matching sia molto inefficace. Con zsh -o extendedglob
, puoi accorciarlo a:
memfree=${${"$(</proc/meminfo)"##*MemFree: #}%%$'\n'*}
Nota che ^
è speciale in molte conchiglie (Bourne, fish, rc, es e zsh con almeno l'opzione extendedglob), ti consiglio di citarlo. Si noti inoltre che echo
non può essere utilizzato per generare dati arbitrari (da qui il mio uso di cui printf
sopra).