Estoy tratando de entender cómo funcionan las canalizaciones con nombre para poder optimizar mi comunicación unidireccional entre procesos. Espero algunos gastos generales debido a la copia de datos en un búfer circular, que habría pensado que está almacenado en la RAM, por lo que esperaba que la tubería fuera mucho más rápida que escribir en un archivo (porque la RAM es un orden de magnitud más rápido que el disco).
En cambio, descubrí que la tubería con nombre (o tubería anónima) tiene aproximadamente la misma velocidad que un archivo. Esto está en un escritorio de 3 GHz con una unidad de disco normal (no de estado sólido), ejecutando Ubuntu Linux. Aquí hay un programa de prueba simplificado en Python:
import sys
import time
import random
megabyte = "".join(random.choice("abcdefghijklmnopqrstuvwxyz") for x in range(1024**2))
while True:
before = time.time()
sys.stdout.write(megabyte)
after = time.time()
sys.stderr.write("{} microseconds\n".format(1e6 * (after - before)))
Tubería directamente a /dev/null
:
python test.py > /dev/null
produce 2.1 microsegundos (constante) para cada megabyte.
Tubería a un archivo:
python test.py > /tmp/testout.txt
salta entre 500 microsegundos y 930 microsegundos (el valor más grande se vuelve más común a medida que el archivo se hace más grande, presumiblemente, está buscando espacio en el disco).
Entonces la tubería nombrada:
mkfifo testpipe
cat testpipe > /dev/null &
python test.py > testpipe
produce 640 microsegundos (constante) y una tubería sin nombre:
python test.py | cat > /dev/null
también produce 650 microsegundos (constante).
¿Alguien puede explicar por qué la velocidad de la tubería se parece más a la velocidad del archivo que a la velocidad del archivo /dev/null
? ¿Podría tener un conmutador en alguna parte que diga "pasar tuberías a través de un búfer basado en archivos, en lugar de un búfer basado en RAM", y puedo cambiar ese conmutador? ¿Podría ser una opción de kernel o una variable de shell?
Otra interpretación: suponga que la salida del disco salta entre 500 y 930 microsegundos porque el 500 es solo tubería y el 930 en realidad está escribiendo. Entonces el 500 ~ 640 para tuberías en ambos casos es equivalente. Sin embargo, según esa interpretación, ¿por qué solo hay un factor de dos entre la tubería y la escritura en el disco? Los sitios web que hablan sobre discos RAM dicen que los discos RAM son 50-200 veces más rápidos que los discos duros.
/dev/null
realidad es bastante barato, mientras que escribir en cualquier otro lugar, ya sea un archivo, un FIFO, una tubería o lo que sea, es mucho más costoso ya que requiere "mucho" esfuerzo de manejo.Respuestas:
No está viendo ningún beneficio de rendimiento porque en realidad no está golpeando el disco cuando usa un archivo: los datos están en camino al disco, pero su hilo de ejecución no necesita esperar a que aterrice allí, por lo que está sin ver realmente la penalización de velocidad de golpear el disco.
Si desea esperar a que se complete la operación del disco para ver cuánto más lento se vuelve, llame a
sync()
(cómo varía en su versión de Python, consulte aquí ): verá decenas de miles de microsegundos solo para que su disco busque un par de veces para escribir el archivo (suponiendo que no tenga algún tipo de caché de escritura rápida como en un controlador RAID).fuente
sync()
tiempo de escritura en disco se convierte en 74,000 microsegundos en promedio. (Loflush()
que estaba haciendo en una variación de mi prueba no lo hizo). Entonces, mi interpretación de que los 500 ~ 640 microsegundos por megabyte es realmente la sobrecarga de la tubería tiene sentido, gracias.