web-dev-qa-db-fra.com

Quelles sont les différences entre poll et select?

Je fais référence au standard POSIX select et poll appels API C du système.

153
Sasha

Je pense que this répond à votre question:

De Richard Stevens ([email protected]):

La différence fondamentale est que fd_set de select () est un masque de bits et a donc une taille fixe. Il serait possible pour le noyau de ne pas limiter cette taille lors de la compilation, ce qui permettrait à l'application de définir FD_SETSIZE comme bon lui semble (comme l'indiquent les commentaires dans l'en-tête du système aujourd'hui), mais cela demande plus de travail. Le noyau 4.4BSD et la fonction de bibliothèque Solaris ont tous deux cette limite. Mais je vois que BSD/OS 2.1 a maintenant été codé pour éviter cette limite, donc c'est faisable, juste une petite question de programmation. :-) Quelqu'un devrait déposer un rapport de bogue Solaris à ce sujet et voir s'il était corrigé.

Avec poll (), cependant, l'utilisateur doit allouer un tableau de structures pollfd et transmettre le nombre d'entrées dans ce tableau, il n'y a donc pas de limite fondamentale. Comme le remarque Casper, moins de systèmes ont poll () que select, ce dernier est donc plus portable. De plus, avec les implémentations d'origine (SVR3), vous ne pouviez pas définir le descripteur sur -1 pour indiquer au noyau d'ignorer une entrée dans la structure pollfd, ce qui rendait difficile la suppression d'entrées du tableau. SVR4 contourne cela. Personnellement, j'utilise toujours select () et rarement poll (), car je transfère aussi mon code dans les environnements BSD. Quelqu'un pourrait écrire une implémentation de poll () qui utilise select () pour ces environnements, mais je n'en ai jamais vu. Les méthodes select () et poll () sont en cours de normalisation par POSIX 1003.1g.

Mise à jour d'octobre 2017:

Le courrier électronique mentionné ci-dessus est au moins aussi ancien que 2001; la commande poll() est maintenant (2017) prise en charge par tous les systèmes d'exploitation modernes, y compris BSD. En fait, certaines personnes pensent que select()doit être déconseillé . Mis à part les opinions, les problèmes de portabilité autour de poll() ne sont plus un problème pour les systèmes modernes. De plus, epoll() a depuis été développé (vous pouvez lire la page de manuel ) et continue de gagner en popularité.

Pour le développement moderne, vous ne voulez probablement pas utiliser select(), bien que rien ne s'y oppose explicitement. poll(), et son évolution plus moderne epoll(), offrent les mêmes fonctionnalités (et plus) que select() sans en subir les limitations.

81
akappa

L'appel select() vous permet de créer trois masques de bit pour indiquer les sockets et les descripteurs de fichier que vous souhaitez surveiller en lecture, en écriture et les erreurs, puis le système d'exploitation indique ceux qui ont eu une activité quelconque; poll() vous a-t-il créé une liste d'ID de descripteurs, et le système d'exploitation les marque chacun avec l'événement kind.

La méthode select() est plutôt maladroite et inefficace.

  1. Plus d'un millier de descripteurs de fichiers potentiels sont disponibles pour un processus. Si un processus long n'a que quelques descripteurs ouverts, mais qu'un nombre élevé a été affecté à l'un d'entre eux, le masque binaire transmis à select() doit être suffisamment grand pour accueillir le descripteur le plus élevé - donc Des plages entières de centaines de bits seront désactivées et le système d’exploitation devra effectuer une boucle sur chaque appel select() juste pour découvrir qu’elles ne sont pas définies.

  2. Une fois que select() est revenu, l'appelant doit parcourir les trois masques de bits pour déterminer les événements survenus. Dans de très nombreuses applications typiques, un ou deux descripteurs de fichier seulement génèrent un nouveau trafic à un moment donné. Cependant, les trois masques de bits doivent être lus jusqu'à la fin pour savoir de quels descripteurs il s'agit.

  3. Étant donné que le système d'exploitation vous signale une activité en réécrivant les masques de bits, ceux-ci sont ruinés et ne sont plus marqués de la liste des descripteurs de fichier que vous souhaitez écouter. Vous devez soit reconstruire tout le masque de bits à partir d'une autre liste que vous gardez en mémoire, soit conserver une copie de chaque masque de bits et memcpy() le bloc de données situé au-dessus des masques de bits en ruine après chaque select() appel.

Ainsi, l'approche poll() fonctionne beaucoup mieux car vous pouvez continuer à réutiliser la même structure de données.

En fait, poll() a inspiré un autre mécanisme dans les noyaux Linux modernes: epoll() qui améliore encore le mécanisme pour permettre un nouveau bond en avant en matière d'évolutivité, les serveurs d'aujourd'hui voulant souvent des milliers de connexions à la fois. C'est une bonne introduction à l'effort:

http://scotdoyle.com/python-epoll-howto.html

Alors que ce lien contient quelques jolis graphiques montrant les avantages de epoll() (vous remarquerez que select()) est à ce stade considéré comme tellement inefficace et démodé qu’il n’a même pas de ligne ces graphiques!):

http://lse.sourceforge.net/epoll/index.html


Mise à jour: Voici une autre question de Stack Overflow, dont la réponse donne encore plus de détails sur les différences:

mises en garde des réacteurs select/poll contre epoll dans Twisted

219
Brandon Rhodes