J'ai un canal nommé sous Linux et je veux le lire à partir de python. Le problème est que le processus python "consomme" un cœur (100%) en continu. Mon code est le suivant:
FIFO = '/var/run/mypipe'
os.mkfifo(FIFO)
with open(FIFO) as fifo:
while True:
line = fifo.read()
Je veux demander si le "sommeil" aidera la situation ou le processus à perdre certaines données d'entrée du tuyau. Je ne peux pas contrôler l'entrée, donc je ne connais pas la fréquence d'entrée des données. J'ai lu sur select et poll mais je n'ai pas trouvé d'exemple pour mon problème. Enfin, je veux demander si l'utilisation à 100% aura un impact sur l'entrée de données (perte ou quelque chose?).
edit: je ne veux pas rompre la boucle. Je veux que le processus s'exécute en continu et "entende" les données du tuyau.
De manière UNIX typique, read(2)
renvoie 0 octet pour indiquer la fin du fichier, ce qui peut signifier:
Dans votre cas, fifo.read()
renvoie une chaîne vide, car le rédacteur a fermé son descripteur de fichier.
Vous devez détecter ce cas et sortir de votre boucle:
reader.py :
import os
import errno
FIFO = 'mypipe'
try:
os.mkfifo(FIFO)
except OSError as oe:
if oe.errno != errno.EEXIST:
raise
print("Opening FIFO...")
with open(FIFO) as fifo:
print("FIFO opened")
while True:
data = fifo.read()
if len(data) == 0:
print("Writer closed")
break
print('Read: "{0}"'.format(data))
Exemple de session
Terminal 1:
$ python reader.py
Opening FIFO...
<blocks>
Terminal 2:
$ echo -n 'hello' > mypipe
Terminal 1:
FIFO opened
Read: "hello"
Writer closed
$
Vous indiquez que vous souhaitez continuer à écouter les écritures sur la pipe, probablement même après la fermeture d'un écrivain.
Pour le faire efficacement, vous pouvez (et devriez) profiter du fait que
Normalement, l'ouverture des blocs FIFO jusqu'à ce que l'autre extrémité soit également ouverte.
Ici, j'ajoute une autre boucle autour de open
et de la boucle read
. De cette façon, une fois le canal fermé, le code tentera de le rouvrir, ce qui bloquera jusqu'à ce qu'un autre écrivain ouvre le canal:
import os
import errno
FIFO = 'mypipe'
try:
os.mkfifo(FIFO)
except OSError as oe:
if oe.errno != errno.EEXIST:
raise
while True:
print("Opening FIFO...")
with open(FIFO) as fifo:
print("FIFO opened")
while True:
data = fifo.read()
if len(data) == 0:
print("Writer closed")
break
print('Read: "{0}"'.format(data))
Terminal 1:
$ python reader.py
Opening FIFO...
<blocks>
Terminal 2:
$ echo -n 'hello' > mypipe
Terminal 1:
FIFO opened
Read: "hello"
Writer closed
Opening FIFO...
<blocks>
Terminal 2:
$ echo -n 'hello' > mypipe
Terminal 1:
FIFO opened
Read: "hello"
Writer closed
Opening FIFO...
<blocks>
... etc.
Vous pouvez en savoir plus en lisant la page man
pour les tuyaux:
(Des années plus tard) Si je comprends le cas d'utilisation de l'OP en utilisant for ... in ...
fait exactement ce que l'on souhaite:
import os
FIFO = 'myfifo'
os.mkfifo(FIFO)
with open(FIFO) as fifo:
for line in fifo:
print(line)
Ce programme attend patiemment l'entrée du fifo jusqu'à ce qu'il soit fourni, puis l'imprime à l'écran. Aucun CPU n'est utilisé entre-temps.
C'est aussi la manière la plus idiomatique de Python donc je le recommanderais plutôt que d'utiliser read () directement.
Si le côté client écrit sur le fifo se ferme, la boucle for se termine et le programme se ferme. Si vous vouliez qu'il rouvre le fifo pour attendre que le prochain client l'ouvre, vous pouvez mettre la section for
dans une boucle while:
import os
FIFO = 'myfifo'
os.mkfifo(FIFO)
while True:
with open(FIFO) as fifo:
for line in fifo:
print(line)
Cela rouvrira le fifo et attendra comme d'habitude.