Ejecuté un script simple para generar un archivo csv grande (10000000 líneas) con 6 campos en los que algunos campos cambiaron en cada línea/fila, usando un while círculo. La máquina tenía todas las (32) CPU libres, gran cantidad de RAM (~31 Gb) también estaba libre.
Cronometré el guión con el comando
/usr/bin/tiempo -v script bash.01.sh
Después de correr durante aproximadamente 2 horas, obtuve las siguientes estadísticas:
Comando cronometrado:“bash script.01.sh”
Tiempo del usuario (segundos):1195.14
Tiempo del sistema (segundos):819.71
Porcentaje de CPU que obtuvo este trabajo:27%
Tiempo transcurrido (reloj de pared) (h:mm:ss o m:ss):2:01:10
Tamaño promedio de texto compartido (kbytes):0
Tamaño promedio de datos no compartidos (kbytes) ):0
Tamaño promedio de pila (kbytes):0
Tamaño promedio total (kbytes):0
Tamaño máximo del conjunto residente (kbytes):4976
Tamaño promedio del conjunto residente (kbytes) ):0
Fallos de página mayores (que requieren E/S):0
Fallos de página menores (recuperación de un marco):3131983488
Cambios de contexto voluntarios:22593141
Cambios de contexto involuntarios:10923348
Intercambios:0
Entradas del sistema de archivos:0
Salidas del sistema de archivos:2182920
Mensajes de socket enviados:0
Mensajes de socket recibidos:0
Señales entregadas:0
Tamaño de página (bytes):4096
Estado de salida:0
Quiero saber por qué mi script usó solo el 27% de la CPU. El disco IO no era mucho en absoluto (se vio en la salida de vmstat). Entonces, ¿qué causó la restricción? ¿El código en el script?
Aquí está el guión:
#!/usr/bin/env bash
number=1
while [[ $number -lt 10000001 ]] ; do
fname="FirstName LastName $"
lname=""
email="[email protected]"
password="1234567890"
altemail="[email protected]"
mobile="9876543210"
echo "$fname,$lname,$email,$password,$altemail,$mobile" >> /opt/list.csv
number=$(expr $number + 1)
done
Respuesta aceptada:
Usando strace
, vi que la línea
number=$(expr $number + 1)
provoca una bifurcación, búsqueda de ruta y ejecución de expr
. (Estoy usando bash 4.2.45 en Ubuntu). Esa sobrecarga del sistema de archivos, el disco y el proceso hizo que bash solo obtuviera alrededor del 28 % de la CPU.
Cuando cambié esa línea para usar solo operaciones integradas de shell
((number = number + 1))
bash usó alrededor del 98% de la CPU y el script se ejecutó en media hora. Esto fue en un Celeron de 1,5 GHz de una sola CPU.
El script tal como está no hace nada que se ejecute en paralelo, por lo que tener 32 CPU libres no ayudará mucho. Sin embargo, ciertamente puede paralelizarlo, por ejemplo, dividiéndolo en 10 bucles de 1 millón de iteraciones que se ejecutan en paralelo, escribiendo en 10 archivos diferentes y luego usando cat
para combinarlos.
El siguiente programa de muestra fue agregado por @Arthur2e5:
max=1000000 step=40000 tmp="$(mktemp -d)"
# Spawning. For loops make a bit more sense in a init-test-incr pattern.
for ((l = 0; l < max; l += step)); do (
for ((n = l + 1, end = (step + l > max ? max : step + l);
n <= end; n++)); do
# Putting all those things into the `buf` line gives you a 1.8x speedup.
fname="FirstName LastName \$"
lname=""
email="[email protected]"
password="1234567890"
altemail="[email protected]"
mobile="9876543210"
buf+="$fname,$lname,$email,$password,$altemail,$mobile"$'\n'
done
printf '%s\n' "$buf" > "$tmp/$l" ) &
done # spawning..
wait
# Merging. The filename order from globbing will be a mess,
# since we didn't format $l to some 0-prefixed numbers.
# Let's just do the loop again.
for ((l = 0; l < max; l += step)); do
printf '%s\n' "$(<"$tmp/$l")" >> /opt/list.csv
done # merging..
rm -rf -- "$tmp" # cleanup