En un bashscript necesito varios valores de /proc/archivos. Hasta ahora tengo docenas de líneas agrupando los archivos directamente así:
grep -oP '^MemFree: *\K[0-9]+' /proc/meminfo
En un esfuerzo por hacerlo más eficiente, guardé el contenido del archivo en una variable y seleccioné eso:
a=$(</proc/meminfo)
echo "$a" | grep -oP '^MemFree: *\K[0-9]+'
En lugar de abrir el archivo varias veces, esto debería abrirlo una sola vez y seleccionar el contenido variable, que supuse sería más rápido, pero de hecho es más 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
Lo mismo es cierto para dashy zsh. Sospeché el estado especial de los /proc/archivos como una razón, pero cuando copio el contenido de /proc/meminfoun archivo normal y uso que los resultados son los mismos:
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
El uso de una cadena here para guardar la tubería lo hace un poco más rápido, pero aún no tan rápido como con los archivos:
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 qué abrir un archivo más rápido que leer el mismo contenido de una variable?

/proc/archivos como una razón, pero cuando copio el contenido de/proc/meminfoun archivo normal y el uso que los resultados son los mismos:” Es no especial/proc/archivos, ¡leer archivos normales también es más rápido!Respuestas:
Aquí, no se trata de abrir un archivo en lugar de leer el contenido de una variable, sino más bien de bifurcar un proceso adicional o no.
grep -oP '^MemFree: *\K[0-9]+' /proc/meminfobifurca un proceso que se ejecuta ygrepque se abre/proc/meminfo(un archivo virtual, en la memoria, sin E / S de disco involucrado) lo lee y coincide con la expresión regular.La parte más costosa es bifurcar el proceso y cargar la utilidad grep y sus dependencias de la biblioteca, hacer la vinculación dinámica, abrir la base de datos de configuración regional, docenas de archivos que están en el disco (pero probablemente en caché en la memoria).
La parte sobre leer
/proc/meminfoes insignificante en comparación, el núcleo necesita poco tiempo para generar la información allí ygrepnecesita poco tiempo para leerlo.Si se ejecuta
strace -cen eso, verá que las llamadas a los sistemas unoopen()y unoread()utilizados para leer/proc/meminfoson cacahuetes en comparación con todo lo demás.grephace para comenzar (strace -cno cuenta la bifurcación).En:
En la mayoría de los depósitos que soportan eso
$(<...)operador ksh, el shell simplemente abre el archivo y lee su contenido (y elimina los caracteres de la nueva línea final).bashes diferente y mucho menos eficiente, ya que bifurca un proceso para hacer esa lectura y pasa los datos al padre a través de una tubería. Pero aquí, se hace una vez, así que no importa.En:
El caparazón necesita generar dos procesos, que se ejecutan simultáneamente pero interactúan entre sí a través de una tubería. Esa creación de tubería, derribar y escribir y leer tiene un costo pequeño. El costo mucho mayor es el engendro de un proceso adicional. La programación de los procesos también tiene algún impacto.
Puede encontrar que usar el
<<<operador zsh lo hace un poco más rápido:En zsh y bash, eso se hace escribiendo el contenido de
$aun archivo temporal, que es menos costoso que generar un proceso adicional, pero probablemente no le dará ninguna ganancia en comparación con obtener los datos directamente/proc/meminfo. Eso sigue siendo menos eficiente que su enfoque que copia/proc/meminfoen el disco, ya que la escritura del archivo temporal se realiza en cada iteración.dashno admite cadenas aquí, pero sus documentos heredados se implementan con una tubería que no implica generar un proceso adicional. En:El caparazón crea una tubería, bifurca un proceso. El niño se ejecuta
grepcon su stdin como el extremo de lectura de la tubería, y el padre escribe el contenido en el otro extremo de la tubería.Pero es probable que el manejo de la tubería y la sincronización del proceso sigan siendo más costosos que simplemente obtener los datos directamente
/proc/meminfo.El contenido de
/proc/meminfoes corto y no lleva mucho tiempo producirlo. Si desea guardar algunos ciclos de CPU, desea eliminar las partes costosas: bifurcar procesos y ejecutar comandos externos.Me gusta:
Sin
bashembargo, evite cuyo patrón de coincidencia es muy ineficiente. Conzsh -o extendedglob, puedes acortarlo a:Tenga en cuenta que
^es especial en muchos shells (Bourne, fish, rc, es y zsh con la opción de globo extendido al menos), recomendaría citarlo. También tenga en cuenta queechono se puede utilizar para generar datos arbitrarios (de ahí mi uso de loprintfanterior).fuente
printfusted dice que el shell necesita generar dos procesos, pero ¿no esprintfun shell incorporado?grepy ejecuta.A | B, hay algunos shells como AT&T ksh o zsh que se ejecutanBen el proceso de shell actual si se trata de un comando incorporado o compuesto o de función, no conozco ninguno que se ejecuteAen el proceso actual. En todo caso, para hacer eso, tendrían que manejar SIGPIPE de una manera compleja como si seAestuviera ejecutando en un proceso secundario y sin terminar el shell para que el comportamiento no sea demasiado sorprendente cuandoBsale temprano. Es mucho más fácil ejecutarBel proceso padre.<<<bashno era compatible<<<, solo que el operador vinozshcomo$(<...)vino de ksh.En su primer caso, solo está utilizando la utilidad grep y está buscando algo del archivo
/proc/meminfo,/proces un sistema de archivos virtual, por lo que el/proc/meminfoarchivo está en la memoria y requiere muy poco tiempo para recuperar su contenido.Pero en el segundo caso, está creando una tubería, luego pasa la salida del primer comando al segundo comando usando esta tubería, lo cual es costoso.
La diferencia se debe a
/proc(porque está en la memoria) y a la tubería, consulte el siguiente ejemplo:fuente
Está llamando a un comando externo en ambos casos (grep). La llamada externa requiere una subshell. Bifurcar ese caparazón es la causa fundamental de la demora. Ambos casos son similares, por lo tanto: un retraso similar.
Si desea leer el archivo externo solo una vez y usarlo (desde una variable) varias veces, no salga del shell:
Lo que toma solo alrededor de 0.1 segundos en lugar del 1 segundo completo para la llamada grep.
fuente