logo Debian Debian Debian-France Debian-Facile Debian-fr.org Forum-Debian.fr Debian ? Communautés logo inclusivité

Debian-facile

Bienvenue sur Debian-Facile, site d'aide pour les nouveaux utilisateurs de Debian.

Vous n'êtes pas identifié(e).


L'icône rouge permet de télécharger chaque page du wiki visitée au format PDF et la grise au format ODT → ODT PDF Export

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
doc:programmation:shell:pipe [17/10/2012 18:43]
smolski
doc:programmation:shell:pipe [22/08/2018 14:41] (Version actuelle)
e-miel Ajout de la conclusion
Ligne 1: Ligne 1:
 ====== Pipe ====== ====== Pipe ======
 +
 +  * Objet : Le pipe
 +  * Niveau requis : {{tag>​avisé}}
 +  * Commentaires : //Utiliser le caractère pipe.« | ». // 
 +  * Suivi : {{tag>​à-tester}}
 +    * Création par [[user>​e-miel]] le 20-04-2011 18:31:31
 +    * Testé par <...> le <​...> ​
 +  * Commentaires sur le forum : [[http://​debian-facile.org/​viewtopic.php?​id=3804 | Lien vers le forum concernant ce tuto]]((N'​hésitez pas à y faire part de vos remarques, succès, améliorations ou échecs !))
 +
 +
  
 ===== Introduction ===== ===== Introduction =====
  
-Les redirections d'​entrée/​sortie(([[manuel:redirection ​| Les redirections en commande]])) permettent de rediriger les résultats vers un fichier. \\+Le caractère pipe est « | » et s'​obtient avec la combinaison de touches : <​key>​Alt Gr</​key>​ avec le <​key>​6</​key>​ du clavier des **lettres**. 
 + 
 +Les redirections d'​entrée/​sortie(([[:​doc:​programmation:​shell:​chevrons ​| Les redirections en commande]])) permettent de rediriger les résultats vers un fichier. \\
 Ce fichier peut ensuite être réinjecté dans un filtre pour en extraire d'​autres résultats.\\ Ce fichier peut ensuite être réinjecté dans un filtre pour en extraire d'​autres résultats.\\
-Cela oblige à taper deux lignes : une pour la redirection vers un fichier, l'​autre pour rediriger ce fichier vers le filtre.+Cela oblige à taper deux lignes : 
 +  - une pour la redirection vers un fichier, 
 +  - l'​autre pour rediriger ce fichier vers le filtre.
  
-Les tubes ou pipes permettent de rediriger directement le canal de sortie -> d'une commande vers -> le canal d'​entrée d'​autre. Le caractère pipe est « | ».+Les tubes ou pipes permettent de rediriger directement le canal de sortie -> d'une commande vers -> le canal d'​entrée d'​autre.
  
 Ainsi, les 2 redirections suivantes : Ainsi, les 2 redirections suivantes :
-<​code ​bash> +<​code ​user>ls -l > resultat.txt</​code>​
-ls -l > resultat.txt</​code>​+
  
 Puis : Puis :
-<​code ​bash> +<​code ​user>wc < resultat.txt</​code>​
-wc < resultat.txt</​code>​+
  
 Deviennent cette commande unique : Deviennent cette commande unique :
-<​code ​bash> +<​code ​user>ls -l | wc</​code>​
-ls -l | wc</​code>​+
  
 Il est possible de placer plusieurs « | » sur une même ligne.</​code>​ Il est possible de placer plusieurs « | » sur une même ligne.</​code>​
-<​code ​bash> +<​code ​user>ls -l | wc | wc</​code>​ 
-ls -l | wc | wc +         ​1 ​        ​3 ​        24
-         ​1 ​        ​3 ​        24</​code>​+
  
-La première commande n'est pas forcément un filtre. L'​essentiel est qu'un résultat soit délivré. Idem pour la dernière commande qui peut par exemple être une commande d'une édition ou d' impression.+La première commande n'est pas forcément un filtre. L'​essentiel est qu'un résultat soit délivré. ​\\ 
 +Idem pour la dernière commande qui peut par exemple être une commande d'une édition ou d'​impression.
  
 Enfin, la dernière commande peut elle-même faire l'​objet d'une redirection en sortie. Enfin, la dernière commande peut elle-même faire l'​objet d'une redirection en sortie.
-<​code ​bash> +<​code ​user>ls -l | wc > resultat.txt</​code>​ 
-ls -l | wc > resultat.txt</​code>​+ 
 + 
 +<note tip>Bien que ce ne soit pas un problème de mettre un espace à la suite d'un **pipe**, pourvu que ce soit bien un espace et pas autre chose. \\ 
 +En fait, ce n'est pas l'​espace qui peut introduire une erreur d'​interprétation,​ mais par exemple, si tu tapes //un espace insécable//,​ pour le [[doc:​programmation:​shell:​shell|shell]] cet //espace insécable//​ n'est pas un délimiteur de mot et donc il analyse l'//​espace insécable//​ représenté de manière non visible comme faisant partie du mot qui le suit ce qui peut engendrer une erreur de sortie. 
 + 
 +Par sécurité, nous pouvons donc rédiger les commandes utilisant **pipe** sans espace dans la redirection. \\ 
 +Exemple : 
 +<code bash>​commande1 |commande2 |Tchibâââ</​code>​ 
 + 
 +**Remarque :** \\ 
 +//Ce qui vaut pour le pipe |, vaut également pour la redirection > amha// 
 +</​note>​ 
  
 ===== Fonctionnement en détail ===== ===== Fonctionnement en détail =====
Ligne 36: Ligne 59:
 Un //pipe// permet à deux processus de s'​échanger des données. Les commandes Shell permettent de créer facilement un //pipe// : Un //pipe// permet à deux processus de s'​échanger des données. Les commandes Shell permettent de créer facilement un //pipe// :
   envoyeur | receveur   envoyeur | receveur
-Dans cet exemple, la sortie standard de **envoyeur** est reliée à l'​entrée standard de **receveur**. Le Shell est un outil très pratique pour créer un //pipe//, mais en aucun cas les données du //pipe// ne transiteront par le Shell lors de l'​exécution. Un //pipe// est aussi appelé FIFO (First In First Out) cela signifie que les données qui sortiront en premier de **envoyeur** seront également les données qui rentreront en premier dans **receveur**. 
  
-Cependant, l'​ordre est celui dans lequel les appels-système à WRITE et READ ont été invoqués, pas l'​ordre dans lequel les processus tentent de les réaliser. Par défaut, les //pipe// sont bloquants, ce qui signifie que lorsque **envoyeur** écrit dans le //pipe//, il s'​endort jusqu'​à ce que le processus **receveur** ait terminé de TOUT lire, ce qui réveille **envoyeur**. Si **receveur** est prêt à lire dans le //pipe// mais qu'​**envoyeur** n'y a encore rien écrit, **receveur** s'​endort et se réveillera dès qu'il y aura quelque chose à lire.+Dans cet exemple, la sortie standard de **envoyeur** est reliée à l'​entrée standard de **receveur**. \\ 
 +Le Shell est un outil très pratique pour créer un //pipe//, mais en aucun cas les données du //pipe// ne transiteront par le Shell lors de l'​exécution. \\ 
 +Un //pipe// est aussi appelé FIFO (First In First Out) cela signifie que les données qui sortiront en premier de **envoyeur** seront également les données qui rentreront en premier dans **receveur**. 
 + 
 +Cependant, l'​ordre est celui dans lequel les appels-système à WRITE et READ ont été invoqués, pas l'​ordre dans lequel les processus tentent de les réaliser. 
 + 
 +Par défaut, les //pipe// sont bloquants, ce qui signifie que lorsque **envoyeur** écrit dans le //pipe//, il s'​endort jusqu'​à ce que le processus **receveur** ait terminé de TOUT lire, ce qui réveille **envoyeur**. ​\\ 
 +Si **receveur** est prêt à lire dans le //pipe// mais qu'​**envoyeur** n'y a encore rien écrit, **receveur** s'​endort et se réveillera dès qu'il y aura quelque chose à lire.
  
-Lorsque vous programmez une application,​ vous pouvez choisir de rendre les //pipes// non-bloquants,​ grâce au flag O_NDELAY ou O_NONBLOCK. Un //pipe// peut très bien être bloquant d'un côté et non-bloquant de l'​autre côté. L'​ordre de réception des données peut différer suivant que le //pipe// soit bloquant (par défaut) ou non-bloquant (flag O_NDELAY).+Lorsque vous programmez une application,​ vous pouvez choisir de rendre les //pipes// non-bloquants,​ grâce au flag O_NDELAY ou O_NONBLOCK. ​\\ 
 +Un //pipe// peut très bien être bloquant d'un côté et non-bloquant de l'​autre côté. ​\\ 
 +L'​ordre de réception des données peut différer suivant que le //pipe// soit bloquant (par défaut) ou non-bloquant (flag O_NDELAY).
  
 ===== Testons le pipe en pratique ===== ===== Testons le pipe en pratique =====
 +
 +<note tip>​Cette partie technique ne concerne que des personnes très avisées ! ^_^</​note>​
  
 Afin que vous puissiez expérimenter par vous-même le fonctionnement d'un //pipe//, je vous ai préparé deux commandes: **rd** (pour READ) et **wr** (pour WRITE) dont voici le code source **src.c**: Afin que vous puissiez expérimenter par vous-même le fonctionnement d'un //pipe//, je vous ai préparé deux commandes: **rd** (pour READ) et **wr** (pour WRITE) dont voici le code source **src.c**:
Ligne 105: Ligne 138:
 Compilez-le avec : Compilez-le avec :
  
-  ​gcc -s -lrt -Wall -std=gnu99 -o rd src.c +<code user>gcc -s -lrt -Wall -std=gnu99 -o rd src.c</​code>​ 
-  ln -s rd wr+<code user>ln -s rd wr</​code>​
  
 À présent, vous vous retrouvez avec deux commandes supplémentaires : À présent, vous vous retrouvez avec deux commandes supplémentaires :
Ligne 122: Ligne 155:
  
 Un cas d'​école,​ non-représentatif de la complexité des véritables applications : Un cas d'​école,​ non-représentatif de la complexité des véritables applications :
-  ​wr 3s30k | rd 2s30k+<code user>wr 3s30k | rd 2s30k</​code>​ 
 Dans cet exemple, **wr** et **rd** sont lancés simultanément et reliés grâce à un //pipe// créé par le Shell. **rd** va attendre 2 secondes puis tenter de lire 30ko dans le //pipe//, mais comme il n'y a encore rien à lire, **rd** va être mis en sommeil. **wr** attend 3 secondes puis écrit 30ko dans le //pipe//, ce qui va réveiller **rd** (qui aura dormi 1 seconde) avec les données demandées. Dans cet exemple, la copie s'est faite directement de la mémoire virtuelle de **wr** à la mémoire virtuelle de **rd** sans transiter par aucun tampon intermédiaire. Les processus **wr** et **rd** se réveillent une fois que Linux a copié les 30ko de données. Dans cet exemple, **wr** et **rd** sont lancés simultanément et reliés grâce à un //pipe// créé par le Shell. **rd** va attendre 2 secondes puis tenter de lire 30ko dans le //pipe//, mais comme il n'y a encore rien à lire, **rd** va être mis en sommeil. **wr** attend 3 secondes puis écrit 30ko dans le //pipe//, ce qui va réveiller **rd** (qui aura dormi 1 seconde) avec les données demandées. Dans cet exemple, la copie s'est faite directement de la mémoire virtuelle de **wr** à la mémoire virtuelle de **rd** sans transiter par aucun tampon intermédiaire. Les processus **wr** et **rd** se réveillent une fois que Linux a copié les 30ko de données.
 <​note>​Cet exemple est naïf, car les processus envoyeur et receveur ne sont pas censés utiliser "comme par hasard"​ des paquets de même taille (ici 30ko) pour transférer les données.</​note>​ <​note>​Cet exemple est naïf, car les processus envoyeur et receveur ne sont pas censés utiliser "comme par hasard"​ des paquets de même taille (ici 30ko) pour transférer les données.</​note>​
Ligne 129: Ligne 163:
  
 Tampon automatique,​ **wr** ne se rend compte de rien : Tampon automatique,​ **wr** ne se rend compte de rien :
-  ​wr 2s30k | rd 3s20k+<code user>wr 2s30k | rd 3s20k</​code>​ 
 Dans cet exemple, **wr** attend 2 secondes puis tente d'​écrire 30ko dans le //pipe//. À ce moment, **rd** n'a pas encore fait son READ, donc où vont les 30ko? Linux les stocke provisoirement dans un tampon limité à 16 pages mémoire (sachant qu'une page fait 4ko, le quota par défaut du tampon est de 64ko) en attendant que **rd** veuille bien lire son entrée standard. Le processus **wr** se termine. Une seconde plus tard, **rd** va lire les 20 premiers ko du tampon, sans savoir qu'il n'y a plus personne derrière son entrée standard. Puis **rd** se termine, et Linux va jeter les 10ko non-récupérés. Dans cet exemple, **wr** attend 2 secondes puis tente d'​écrire 30ko dans le //pipe//. À ce moment, **rd** n'a pas encore fait son READ, donc où vont les 30ko? Linux les stocke provisoirement dans un tampon limité à 16 pages mémoire (sachant qu'une page fait 4ko, le quota par défaut du tampon est de 64ko) en attendant que **rd** veuille bien lire son entrée standard. Le processus **wr** se termine. Une seconde plus tard, **rd** va lire les 20 premiers ko du tampon, sans savoir qu'il n'y a plus personne derrière son entrée standard. Puis **rd** se termine, et Linux va jeter les 10ko non-récupérés.
 <​note>​[[http://​www.kernel.org/​doc/​man-pages/​online/​pages/​man2/​fcntl.2.html|fcntl()]] permet de grossir le tampon du //pipe// jusqu'​à 1Mo (ou plus avec l'​intervention du root). Cependant, dans le cas de gros transferts, il est plus efficace de réaliser de grosses copies directes avec des WRITE et READ bloquants, plutôt que de multiplier le nombre de copies pour éviter de dormir... et de toute façon, tampon ou pas, un processus dort TOUJOURS pendant une copie, que cette copie soit bloquante ou non.</​note>​ <​note>​[[http://​www.kernel.org/​doc/​man-pages/​online/​pages/​man2/​fcntl.2.html|fcntl()]] permet de grossir le tampon du //pipe// jusqu'​à 1Mo (ou plus avec l'​intervention du root). Cependant, dans le cas de gros transferts, il est plus efficace de réaliser de grosses copies directes avec des WRITE et READ bloquants, plutôt que de multiplier le nombre de copies pour éviter de dormir... et de toute façon, tampon ou pas, un processus dort TOUJOURS pendant une copie, que cette copie soit bloquante ou non.</​note>​
Ligne 136: Ligne 171:
  
 Comme l'​exemple 2, mais avec un zéro en plus dans les tailles, ça change tout : Comme l'​exemple 2, mais avec un zéro en plus dans les tailles, ça change tout :
-  ​wr 2s300k | rd 3s200k+<code user>wr 2s300k | rd 3s200k</​code>​ 
 **wr** tente d'​écrire 300ko dans le //pipe// et **rd** n'a pas encore fait son READ. Comme le tampon du //pipe// n'est que de 64ko, les données seront donc copiées en prise directe: **wr** s'​endort jusqu'​à ce que **rd** finisse de récupérer les 300ko. Or **rd** ne lit que 200ko, **wr** reste endormi en attendant que **rd** fasse un autre READ, seulement contre toute attente, **rd** se termine, ce qui laisse les données de **wr** en plan. Ne sachant pas gérer la situation, **wr** se tue. **wr** tente d'​écrire 300ko dans le //pipe// et **rd** n'a pas encore fait son READ. Comme le tampon du //pipe// n'est que de 64ko, les données seront donc copiées en prise directe: **wr** s'​endort jusqu'​à ce que **rd** finisse de récupérer les 300ko. Or **rd** ne lit que 200ko, **wr** reste endormi en attendant que **rd** fasse un autre READ, seulement contre toute attente, **rd** se termine, ce qui laisse les données de **wr** en plan. Ne sachant pas gérer la situation, **wr** se tue.
 <​note>​Dans l'​exemple 2, **wr** ne se rendait pas compte que **rd** n'​allait pas récupérer toutes les données, sauf qu'ici le tampon est trop petit et **wr** est donc en prise directe avec **rd**. Grâce à [[http://​www.kernel.org/​doc/​man-pages/​online/​pages/​man2/​signal.2.html|signal()]],​ il aurait été possible de faire réagir **wr** autrement qu'en se suicidant à la réception d'un SIGPIPE, mais cela ne change rien au problème: tout processus receveur est censé attendre la fin du flux de données avant de se terminer. Dans les exemples 2 et 3, **rd** est malpoli.</​note>​ <​note>​Dans l'​exemple 2, **wr** ne se rendait pas compte que **rd** n'​allait pas récupérer toutes les données, sauf qu'ici le tampon est trop petit et **wr** est donc en prise directe avec **rd**. Grâce à [[http://​www.kernel.org/​doc/​man-pages/​online/​pages/​man2/​signal.2.html|signal()]],​ il aurait été possible de faire réagir **wr** autrement qu'en se suicidant à la réception d'un SIGPIPE, mais cela ne change rien au problème: tout processus receveur est censé attendre la fin du flux de données avant de se terminer. Dans les exemples 2 et 3, **rd** est malpoli.</​note>​
Ligne 143: Ligne 179:
  
 Ça devient intéressant,​ et commence à ressembler à la réalité : Ça devient intéressant,​ et commence à ressembler à la réalité :
-  ​wr 2s300k | rd 3s200k 4s200+<code user>wr 2s300k | rd 3s200k 4s200</​code>​ 
 **wr** tente d'​écrire 300ko dans le //pipe//, **rd** récupère 200ko sans utiliser le tampon, puis une seconde plus tard, **rd** tente de récupérer 200ko mais reçoit les 100ko restants, ce qui réveille **wr**. Les 2 processus n'ont plus rien à faire, et se terminent donc simultanément. **wr** tente d'​écrire 300ko dans le //pipe//, **rd** récupère 200ko sans utiliser le tampon, puis une seconde plus tard, **rd** tente de récupérer 200ko mais reçoit les 100ko restants, ce qui réveille **wr**. Les 2 processus n'ont plus rien à faire, et se terminent donc simultanément.
  
Ligne 151: Ligne 188:
  
 Comme l'​exemple 4, mais l'​écriture est non-bloquante : Comme l'​exemple 4, mais l'​écriture est non-bloquante :
-  ​wr -n 2s300k | rd 3s200k 4s200+<code user>wr -n 2s300k | rd 3s200k 4s200</​code>​ 
 **wr** (avec l'​option **-n**) tente d'​écrire 300ko, mais personne n'​attend à l'​autre bout du //pipe//. **wr** va donc remplir les 64ko du tampon du //pipe//. Une seconde plus tard, **rd** tente de lire 200ko et récupère les 64ko stockés dans le tampon. Une seconde plus tard, **rd** tente à nouveau de lire 200ko mais ne récupère rien, car le tampon est vide. **rd** va donc se terminer en ayant récupéré 64ko au lieu de 300ko. **wr** (avec l'​option **-n**) tente d'​écrire 300ko, mais personne n'​attend à l'​autre bout du //pipe//. **wr** va donc remplir les 64ko du tampon du //pipe//. Une seconde plus tard, **rd** tente de lire 200ko et récupère les 64ko stockés dans le tampon. Une seconde plus tard, **rd** tente à nouveau de lire 200ko mais ne récupère rien, car le tampon est vide. **rd** va donc se terminer en ayant récupéré 64ko au lieu de 300ko.
 <​note>​L'​écriture non-bloquante a rendu cet exemple naïf, mais rassurez-vous:​ "​écriture non-bloquante"​ n'est pas nécessairement synonyme de "​pertes de données",​ car on peut s'en sortir avec une boucle, mais, cela consommera beaucoup de ressource CPU et sera de toute façon moins efficace qu'un processus qui dort, car un processus qui dort se réveille toujours au bon moment.</​note>​ <​note>​L'​écriture non-bloquante a rendu cet exemple naïf, mais rassurez-vous:​ "​écriture non-bloquante"​ n'est pas nécessairement synonyme de "​pertes de données",​ car on peut s'en sortir avec une boucle, mais, cela consommera beaucoup de ressource CPU et sera de toute façon moins efficace qu'un processus qui dort, car un processus qui dort se réveille toujours au bon moment.</​note>​
Ligne 158: Ligne 196:
  
 Comme l'​exemple 1, mais la lecture est non-bloquante : Comme l'​exemple 1, mais la lecture est non-bloquante :
-  ​wr 3s30k | rd -n 2s30k+<code user>wr 3s30k | rd -n 2s30k</​code>​ 
 **rd** (avec l'​option **-n**) tente de lire 30ko, mais il n'y a rien à lire. Au lieu de s'​endormir en attendant que **wr** fasse un WRITE, **rd** va tout simplement passer à la suite, c'​est-à-dire se terminer. Une seconde plus tard, **wr** va vouloir écrire 30ko, mais comme il n'y a personne à l'​autre bout du //pipe//, **wr** va recevoir un SIGPIPE et se suicider. **rd** (avec l'​option **-n**) tente de lire 30ko, mais il n'y a rien à lire. Au lieu de s'​endormir en attendant que **wr** fasse un WRITE, **rd** va tout simplement passer à la suite, c'​est-à-dire se terminer. Une seconde plus tard, **wr** va vouloir écrire 30ko, mais comme il n'y a personne à l'​autre bout du //pipe//, **wr** va recevoir un SIGPIPE et se suicider.
 <​note>​L'​exemple 1, qui fonctionnait parfaitement,​ échoue si l'on rend la lecture non-bloquante.</​note>​ <​note>​L'​exemple 1, qui fonctionnait parfaitement,​ échoue si l'on rend la lecture non-bloquante.</​note>​
Ligne 170: Ligne 209:
 === WRITE > READ === === WRITE > READ ===
  
-  ​wr 1s10k300k7k 2s5k 4s200k | rd 0s2k 3s5000k 5s6k +<code user>wr 1s10k300k7k 2s5k 4s200k | rd 0s2k 3s5000k 5s6k</​code>​ 
 +<file config retour de la commande>​
   (1s) 1.0s    10k >   (1s) 1.0s    10k >
   (0s) 1.0s        >    2k   (0s) 1.0s        >    2k
Ligne 180: Ligne 219:
   (5s) 5.0s        >    6k   (5s) 5.0s        >    6k
        ​5.0s ​       > CLOSE        ​5.0s ​       > CLOSE
-       ​5.0s ​ CLOSE >+       ​5.0s ​ CLOSE ></​file>
  
 <​note>​Il se passe 2 secondes entre la dernière action de **wr** et la fermeture du //pipe//, **wr** a donc été tué durant son sommeil.</​note>​ <​note>​Il se passe 2 secondes entre la dernière action de **wr** et la fermeture du //pipe//, **wr** a donc été tué durant son sommeil.</​note>​
Ligne 186: Ligne 225:
 === WRITE non-bloquant > READ === === WRITE non-bloquant > READ ===
  
-  ​wr -n 1s10k300k7k 2s5k 4s200k | rd 0s2k 3s5000k 5s6k +<code user>wr -n 1s10k300k7k 2s5k 4s200k | rd 0s2k 3s5000k 5s6k</​code>​ 
 +<file config retour de la commande>​
   (1s) 1.0s    10k >   (1s) 1.0s    10k >
   (1s) 1.0s    52k >   (1s) 1.0s    52k >
Ligne 197: Ligne 236:
        ​4.0s ​ CLOSE >        ​4.0s ​ CLOSE >
   (5s) 5.0s        >    6k   (5s) 5.0s        >    6k
-       ​5.0s ​       > CLOSE+       ​5.0s ​       > CLOSE</​file>​
  
 <​note>​La majorité des données a été perdue, alors que le scénario est identique au premier, au type d'​écriture près.</​note>​ <​note>​La majorité des données a été perdue, alors que le scénario est identique au premier, au type d'​écriture près.</​note>​
  
-=== WRITE > READ non-blocant ​=== +=== WRITE > READ non-bloquant ​===
- +
-  wr 1s10k300k7k 2s5k 4s200k | rd -n 0s2k 3s5000k 5s6k+
  
 +<code user>wr 1s10k300k7k 2s5k 4s200k | rd -n 0s2k 3s5000k 5s6k</​code>​
 +<file config retour de la commande>​
   (0s) 0.0s        >    0k   (0s) 0.0s        >    0k
   (1s) 1.0s    10k >   (1s) 1.0s    10k >
Ligne 213: Ligne 252:
   (5s) 5.0s        >    6k   (5s) 5.0s        >    6k
        ​5.0s ​       > CLOSE        ​5.0s ​       > CLOSE
-       ​5.0s ​ CLOSE >+       ​5.0s ​ CLOSE ></​file>
  
 <​note>​Comme précédemment,​ on voit que **wr** a été tué durant son sommeil.</​note>​ <​note>​Comme précédemment,​ on voit que **wr** a été tué durant son sommeil.</​note>​
  
-=== WRITE non-blocant ​> READ non-bloquant === +=== WRITE non-bloquant ​> READ non-bloquant ===
- +
-  wr -n 1s10k300k7k 2s5k 4s200k | rd -n 0s2k 3s5000k 5s6k+
  
 +<code user>wr -n 1s10k300k7k 2s5k 4s200k | rd -n 0s2k 3s5000k 5s6k</​code>​
 +<file config retour de la commande>​
   (0s) 0.0s        >    0k   (0s) 0.0s        >    0k
   (1s) 1.0s    10k >   (1s) 1.0s    10k >
Ligne 230: Ligne 269:
        ​4.0s ​ CLOSE >        ​4.0s ​ CLOSE >
   (5s) 5.0s        >    6k   (5s) 5.0s        >    6k
-       ​5.0s ​       > CLOSE+       ​5.0s ​       > CLOSE</​file>​
  
 <​note>​Quasiment toutes les données ont été perdues.</​note>​ <​note>​Quasiment toutes les données ont été perdues.</​note>​
 +
 +
 +===== Conclusion =====
 +
 +<note tip>
 +  * **Pipe bloquant** = comportement par défaut = aucune consommation CPU quand le processus dort = se réveille toujours au bon moment :-)
 +  * **Pipe non bloquant** = problèmes de données perdues et consommation CPU :-(
 +</​note>​
 +
 +L'​immense majorité des programmes ne personnalisent pas le comportement de leurs descripteurs,​ donc si vous utilisez des pipes dans vos scripts, ils seront bloquants :
 +
 +  * Les échanges de //petite taille// : texte brut échangé entre **awk**, **sed**, **bash**, **latex**, et en général tout traitement de script par **python** (choisi pour son efficacité à traiter les expressions régulières) se font implicitement au travers du tampon de 64ko, c'est la solution la plus rapide : chacun des processus participants enchaîne ses nombreux petits traitements internes sans s'​arrêter puis se termine indépendamment de l'​autre processus.
 +
 +  * Les échanges de //grande taille// : vidéo brute échangée entre **ffmpeg**, **x264**, et en général toute compression de grande taille par **gzip**, **xz**, se fait implicitement sans tampon, copie directe de processus à processus durant leur sommeil, c'est la solution la plus rapide : le tampon n'est jamais utilisé même partiellement.
 +
 +<​note>​La quantité de données échangées déterminera si le comportement est **tampon** ou **sommeil**,​ mais dans les deux cas, les pipes sont bloquants.</​note>​
 +
doc/programmation/shell/pipe.1350492220.txt.gz · Dernière modification: 17/10/2012 18:43 par smolski

Pied de page des forums

Propulsé par FluxBB