2 points par GN⁺ 2024-11-30 | 1 commentaires | Partager sur WhatsApp

Pourquoi les pipes « se bloquent » : le buffering

  • Description du problème : quand on exécute la commande tail -f /some/log/file | grep thing1 | grep thing2 pour trouver une sortie précise dans un fichier de log, il peut arriver que rien ne s’affiche si les lignes sont ajoutées lentement. On a alors l’impression que le pipe est bloqué, mais en réalité le programme n’écrit tout simplement pas encore les données dans le pipe.

Cause du buffering

  • Pourquoi il existe : il est courant qu’un programme bufferise les données avant de les écrire dans un pipe ou un fichier. C’est pour des raisons de performance : au lieu d’écrire immédiatement chaque sortie, il accumule une certaine quantité de données puis les écrit d’un coup.
  • Exemple : grep thing1 peut conserver les lignes correspondantes jusqu’à avoir accumulé 8 KB de données, ce qui peut retarder l’affichage.

Pas de buffering lors de l’écriture vers le terminal

  • Différence entre terminal et pipe : grep utilise un buffering par ligne lorsque la sortie va vers un terminal, mais un buffering par blocs lorsqu’elle va vers un pipe. Ce comportement est déterminé via la fonction isatty.

Commandes qui bufferisent et celles qui ne le font pas

  • Commandes non bufferisées : tail, cat, tee, etc. ne bufferisent pas.
  • Commandes bufferisées : grep, sed, awk, tcpdump, jq, tr, cut, etc. bufferisent, et certaines permettent de désactiver ce comportement avec un flag spécifique.

Buffering de sortie par défaut dans les langages de programmation

  • Langages concernés : C, Python, Ruby, Perl, etc. bufferisent la sortie par défaut, avec des moyens spécifiques pour désactiver ce comportement.

Perte du contenu du buffer quand on appuie sur Ctrl-C

  • Description du problème : lorsqu’on appuie sur Ctrl-C, le contenu du buffer est perdu. Cela arrive parce que le signal SIGINT est envoyé en premier.
  • Solution : trouver le PID de tcpdump puis exécuter kill -TERM $PID permet de vider le buffer.

Buffering aussi lors d’une redirection vers un fichier

  • Redirection vers un fichier : il y a aussi du buffering lors d’une redirection vers un fichier, mais sans le problème de perte du buffer causé par Ctrl-C.

Plusieurs façons d’éviter le buffering

  • Solution 1 : exécuter un programme qui se termine rapidement.
  • Solution 2 : utiliser le flag --line-buffered de grep.
  • Solution 3 : utiliser awk.
  • Solution 4 : utiliser stdbuf.
  • Solution 5 : utiliser unbuffer.

Variables d’environnement pour désactiver le buffering

  • Idée : il serait utile d’avoir une variable d’environnement standard comme PYTHON_UNBUFFERED. Une variable comme NO_BUFFER est proposée.

Contenu omis

  • Sujets omis : la différence entre buffering par ligne et absence totale de buffering, la différence de buffering entre stderr et stdout, le buffering du pilote TTY du système d’exploitation, etc.

1 commentaires

 
GN⁺ 2024-11-30
Avis Hacker News
  • Un accès avec buffering doit être vidé après un certain nombre d’octets ou un certain délai. C’est une manière courante de résoudre des problèmes similaires dans les interfaces matérielles

    • Une bibliothèque qui met en buffer dans l’espace utilisateur doit définir un temporisateur approprié lorsqu’elle commence à bufferiser les données
    • Il est préférable que le paramètre de temporisation soit passé en argument, ou soit légèrement inférieur à l’échelle de temps humaine, ou proportionnel à la bande passante / au seuil, ou proportionnel au coût du flush
    • Cela s’applique aussi bien à l’écriture qu’à la lecture, et peut varier selon le canal de données
  • Si le CPU de tout le système devient inactif, on voudrait vider tous les buffers

    • Le buffering est généralement une technique d’économie du CPU
    • Quand le CPU devient inactif, il faudrait envoyer à tous les processus un signal du type « videz vos buffers »
  • Je travaille avec des systèmes NIX depuis plus de 20 ans, mais j’oublie toujours les problèmes de buffering

  • J’utilise Unix depuis plus de 35 ans, mais je n’avais jamais complètement compris le fonctionnement du buffering. Cette explication m’a été utile

  • Il y a une confusion entre « non bufferisé » et « bufferisé par ligne »

    • Le mode non bufferisé peut dégrader les performances et produire une sortie incorrecte lorsque plusieurs sources écrivent dans le même pipeline
    • Le buffering par ligne est la valeur par défaut sur un terminal et convient bien aux pipelines
  • Les buffers existent parce qu’écrire dans un buffer est relativement beaucoup plus lent qu’afficher la sortie à l’écran

    • C’est un problème fréquent lorsqu’on travaille avec l’UART, et il existe diverses solutions
    • Il y a plusieurs approches, comme l’utilisation de caractères spéciaux, une approche basée sur la longueur, ou une approche basée sur le temps
  • Appuyer sur Ctrl-C peut entraîner la perte du contenu du buffer

    • Je pensais que la plupart des programmes vidaient leur buffer à la réception de SIGINT
  • J’ai eu des problèmes de buffering sous Unix, et toutes les implémentations de awk ne se comportent pas de la même manière

  • J’ai l’impression d’avoir raté la blague sur le pipeline gelé