Perché una pipa denominata è lenta come scrivere su un file?


18

Sto cercando di capire come funzionano le named pipe in modo da poter semplificare la mia comunicazione interprocesso unidirezionale. Mi aspetto un sovraccarico a causa della copia dei dati in un buffer circolare, che avrei pensato fosse memorizzato nella RAM, e quindi mi aspettavo che la pipe fosse molto più veloce della scrittura su un file (perché la RAM è ordini di grandezza più veloci del disco).

Invece, ho scoperto che la named pipe (o pipe anonima) ha circa la stessa velocità di un file. Questo è su un desktop a 3 GHz con un normale disco rigido (non a stato solido), con Ubuntu Linux. Ecco un programma di test semplificato in 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)))

Tubazioni dirette a /dev/null:

python test.py > /dev/null

produce 2,1 microsecondi (costante) per ogni megabyte.

Piping su un file:

python test.py > /tmp/testout.txt

salta tra 500 microsecondi e 930 microsecondi (il valore più grande diventa più comune man mano che il file diventa più grande --- presumibilmente, sta cercando spazio su disco).

Quindi la pipa denominata:

mkfifo testpipe
cat testpipe > /dev/null &
python test.py > testpipe

produce 640 microsecondi (costante) e una pipe senza nome:

python test.py | cat > /dev/null

produce anche 650 microsecondi (costante).

Qualcuno può spiegare perché la velocità della pipe è più simile alla velocità del file che /dev/nullalla velocità? Potrei avere un interruttore da qualche parte che dice "esegui pipe attraverso un buffer basato su file, piuttosto che un buffer basato su RAM" e posso cambiare tale interruttore? Potrebbe essere un'opzione del kernel o una variabile di shell?

Un'altra interpretazione: supponiamo che l'uscita del disco salti tra 500 e 930 microsecondi perché la 500 è solo una tubazione e la 930 in realtà sta scrivendo. Quindi i 500 ~ 640 per le tubazioni in entrambi i casi sono equivalenti. Tuttavia, secondo tale interpretazione, perché esiste solo un fattore due tra il piping e la scrittura su disco? I siti Web che parlano di dischi RAM affermano che i dischi RAM sono 50-200 volte più veloci dei dischi rigidi.


1
Scrivere in /dev/nullrealtà è piuttosto economico, mentre scrivere altrove - che si tratti di un file, un FIFO, una pipe o altro - è molto più costoso in quanto richiede "molto" sforzo di gestione.
glglgl,

Risposte:


31

Non stai riscontrando alcun vantaggio in termini di prestazioni perché non stai effettivamente colpendo il disco quando utilizzi un file: i dati stanno arrivando sul disco, ma il tuo thread di esecuzione non ha bisogno di aspettare che finisca lì, quindi sei in realtà non vedendo la penalità di velocità di colpire il disco.

Se vuoi attendere il completamento dell'operazione del disco per vedere quanto rallenta, chiama a sync()(come varia sulla tua versione di Python, vedi qui ) - vedrai decine di migliaia di microsecondi solo per il tuo disco cercare un paio di volte per ottenere il file scritto (supponendo che non abbia una sorta di cache di scrittura veloce come in un controller RAID).


Quando smetteremo di preoccuparci del tempo di ricerca dei nostri dispositivi a blocchi? :)
EEAA

5
@EEAA Tutti gli SSD, sempre.

1
Hai ragione: con un sync()tempo di scrittura su disco diventa in media 74.000 microsecondi. (Quello flush()che stavo facendo in una variante del mio test non lo ha fatto.) Quindi la mia interpretazione che i 500 ~ 640 microsecondi per megabyte è davvero il sovraccarico del tubo ha senso, grazie.
Jim Pivarski,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.