Je fais référence aux appels d'API C standard du système de sélection et d' interrogation POSIX .
Je fais référence aux appels d'API C standard du système de sélection et d' interrogation POSIX .
Réponses:
Je pense que cela répond à votre question:
De Richard Stevens (rstevens@noao.edu):
La différence fondamentale est que le 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 du noyau, permettant à l'application de définir FD_SETSIZE à ce qu'elle veut (comme les commentaires dans l'en-tête du système l'impliquent aujourd'hui) mais cela demande plus de travail. 4.4 Le noyau de BSD 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 si cela est jamais 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 note Casper, moins de systèmes ont poll () que select, donc ce dernier est 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 des entrées du tableau; SVR4 contourne cela. Personnellement, j'utilise toujours select () et rarement poll (), car je porte 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 deux select () et poll () sont normalisés par POSIX 1003.1g.
L'e-mail référencé ci-dessus est au moins aussi vieux que 2001; la poll()
commande est désormais (2017) prise en charge sur tous les systèmes d'exploitation modernes, y compris BSD. En fait, certaines personnes pensent que cela select()
devrait être déconseillé . Opinions mises à part, les problèmes de portabilité poll()
ne sont plus un problème sur 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 qu'il n'y ait rien de mal à cela. poll()
, et c'est une évolution plus moderne epoll()
, offrent les mêmes fonctionnalités (et plus) que select()
sans souffrir des limitations qui s'y trouvent.
select
ou poll
:(
L' select()
appel vous demande de créer trois masques de bits pour marquer les sockets et les descripteurs de fichiers que vous souhaitez surveiller pour la lecture, l'écriture et les erreurs, puis le système d'exploitation marque ceux qui ont en fait eu une sorte d'activité; poll()
avez-vous créé une liste d'identifiants de descripteurs et que le système d'exploitation marque chacun d'eux avec le type d'événement qui s'est produit.
La select()
méthode est plutôt maladroite et inefficace.
Il existe généralement plus d'un millier de descripteurs de fichiers potentiels disponibles pour un processus. Si un processus de longue durée n'a que quelques descripteurs ouverts, mais qu'au moins l'un d'entre eux a reçu un nombre élevé, alors le masque de bits transmis select()
doit être suffisamment grand pour accueillir ce descripteur le plus élevé - des plages entières de centaines de bits ne pas indiquer que le système d'exploitation doit effectuer une boucle à chaque select()
appel juste pour découvrir qu'ils ne sont pas définis.
Une fois select()
retourné, l'appelant doit boucler les trois masques de bits pour déterminer quels événements ont eu lieu. Dans de très nombreuses applications typiques, seuls un ou deux descripteurs de fichier recevront du nouveau trafic à un moment donné, mais les trois masques de bits doivent être lus jusqu'à la fin pour découvrir de quels descripteurs il s'agit.
Étant donné que le système d'exploitation vous signale l'activité en réécrivant les masques de bits, ils sont ruinés et ne sont plus marqués avec la liste des descripteurs de fichiers que vous souhaitez écouter. Soit vous devez reconstruire le masque de bits entier à partir d'une autre liste que vous gardez en mémoire, soit vous devez conserver une copie en double de chaque masque de bits et memcpy()
du bloc de données au-dessus des masques de bits ruinés après chaque select()
appel.
L' poll()
approche fonctionne donc beaucoup mieux car vous pouvez continuer à réutiliser la même structure de données.
En fait, poll()
a inspiré encore un autre mécanisme dans les noyaux Linux modernes: epoll()
ce qui améliore encore plus le mécanisme pour permettre un autre saut dans l'évolutivité, car les serveurs d'aujourd'hui veulent souvent gérer des dizaines de milliers de connexions à la fois. Ceci est une bonne introduction à l'effort:
http://scotdoyle.com/python-epoll-howto.html
Bien que ce lien présente de jolis graphiques montrant les avantages de epoll()
(vous noterez qu'à select()
ce stade, il est considéré comme si inefficace et démodé qu'il n'obtient même pas de ligne sur ces graphiques!):
http://lse.sourceforge.net/epoll/index.html
Mise à jour: Voici une autre question Stack Overflow, dont la réponse donne encore plus de détails sur les différences:
Mises en garde concernant les réacteurs Select / Poll vs Epoll dans Twisted
Les deux sont lents et pour la plupart identiques , mais de taille et de fonctionnalités différentes!
Lorsque vous écrivez un itérateur, vous devez copier l'ensemble de select
chaque fois! Bien que poll
ce genre de problème ait été résolu pour avoir un beau code. Une autre différence est qu'il poll
peut gérer plus de 1024 descripteurs de fichiers (FD) par défaut. poll
peut gérer différents événements pour rendre le programme plus lisible au lieu d'avoir beaucoup de variables pour gérer ce genre de travail. Les opérations dans poll
et select
est linéaire et lent en raison d'avoir beaucoup de contrôles.