Tout ce que j'ai lu et expérimenté (applications basées sur Tornado) me porte à croire que ePoll est un remplacement naturel des réseaux basés sur Select et Poll, en particulier avec Twisted. Ce qui me rend paranoïaque, c'est assez rare pour qu'une meilleure technique ou méthodologie ne vienne pas avec un prix.
La lecture de quelques dizaines de comparaisons entre epoll et les alternatives montre qu'epoll est clairement le champion de la vitesse et de l'évolutivité, en particulier qu'il évolue de manière linéaire, ce qui est fantastique. Cela dit, qu'en est-il de l'utilisation du processeur et de la mémoire, epoll est-il toujours le champion?
Pour un très petit nombre de sockets (varie en fonction de votre matériel, bien sûr, mais nous parlons de quelque chose de l'ordre de 10 ou moins), select peut battre epoll dans l'utilisation de la mémoire et la vitesse d'exécution. Bien sûr, pour un si petit nombre de sockets, les deux mécanismes sont si rapides que vous ne vous souciez pas vraiment de cette différence dans la grande majorité des cas.
Une précision, cependant. Select et epoll sont mis à l'échelle de façon linéaire. Une grande différence, cependant, est que les API orientées espace utilisateur ont des complexités basées sur des choses différentes. Le coût d'un appel select
va à peu près avec la valeur du descripteur de fichier numéroté le plus élevé que vous lui avez transmis. Si vous sélectionnez sur un seul fd, 100, alors c'est à peu près deux fois plus cher que de sélectionner sur un seul fd, 50. Ajouter plus de fds en dessous du plus haut n'est pas tout à fait gratuit, donc c'est un peu plus compliqué que cela dans la pratique, mais cela est une bonne première approximation pour la plupart des implémentations.
Le coût d'epoll est plus proche du nombre de descripteurs de fichiers qui contiennent réellement des événements. Si vous surveillez 200 descripteurs de fichiers, mais que seulement 100 d'entre eux ont des événements, vous ne payez (très gros) que pour ces 100 descripteurs de fichiers actifs. C'est là qu'epoll tend à offrir l'un de ses principaux avantages par rapport à select. Si vous avez mille clients qui sont pour la plupart inactifs, alors lorsque vous utilisez select, vous payez toujours pour mille d'entre eux. Cependant, avec epoll, c'est comme si vous n'en aviez que quelques-uns - vous ne payez que pour ceux qui sont actifs à un moment donné.
Tout cela signifie qu'epoll réduira l'utilisation du processeur pour la plupart des charges de travail. En ce qui concerne l'utilisation de la mémoire, c'est un peu compliqué. select
parvient à représenter toutes les informations nécessaires de manière très compacte (un bit par descripteur de fichier). Et la limitation FD_SETSIZE (généralement 1024) sur le nombre de descripteurs de fichiers que vous pouvez utiliser avec select
signifie que vous ne dépenserez jamais plus de 128 octets pour chacun des trois ensembles fd que vous pouvez utiliser avec select
(lecture, écriture, exception). Comparé à ces 384 octets max, epoll est une sorte de cochon. Chaque descripteur de fichier est représenté par une structure multi-octets. Cependant, en termes absolus, cela n'utilisera toujours pas beaucoup de mémoire. Vous pouvez représenter un grand nombre de descripteurs de fichiers en quelques dizaines de kilo-octets (environ 20k pour 1000 descripteurs de fichiers, je pense). Et vous pouvez également ajouter le fait que vous devez dépenser les 384 de ces octets avec select
si vous ne souhaitez surveiller qu'un seul descripteur de fichier mais que sa valeur se trouve être 1024, alors qu'avec epoll vous ne dépenseriez que 20 octets. Pourtant, tous ces chiffres sont assez petits, donc cela ne fait pas beaucoup de différence.
Et il y a aussi cet autre avantage d'epoll, que vous connaissez peut-être déjà, qu'il n'est pas limité aux descripteurs de fichier FD_SETSIZE. Vous pouvez l'utiliser pour surveiller autant de descripteurs de fichiers que vous en avez. Et si vous n'avez qu'un seul descripteur de fichier, mais que sa valeur est supérieure à FD_SETSIZE, epoll fonctionne également avec cela, mais pas select
.
Au hasard, j'ai également récemment découvert un léger inconvénient de epoll
par rapport à select
ou poll
. Bien qu'aucune de ces trois API ne prenne en charge les fichiers normaux (c'est-à-dire les fichiers sur un système de fichiers), select
et poll
présentent ce manque de prise en charge en signalant ces descripteurs comme toujours lisibles et toujours inscriptibles. Cela les rend impropres à tout type significatif d'E/S de système de fichiers non bloquants, un programme qui utilise select
ou poll
et qui rencontre un descripteur de fichier du système de fichiers continuera au moins à fonctionner. (ou s'il échoue, ce ne sera pas à cause de select
ou poll
), bien que ce ne soit peut-être pas avec les meilleures performances.
D'un autre côté, epoll
échouera rapidement avec une erreur (EPERM
, apparemment) lorsqu'on lui demandera de surveiller un tel descripteur de fichier. À strictement parler, ce n'est guère incorrect. Cela signale simplement son manque de soutien de manière explicite. Normalement, j'applaudirais à des conditions d'échec explicites, mais celle-ci n'est pas documentée (pour autant que je sache) et entraîne une application complètement cassée, plutôt qu'une application qui fonctionne simplement avec des performances potentiellement dégradées.
Dans la pratique, le seul endroit où j'ai vu cela se produire est lors de l'interaction avec stdio. Un utilisateur peut rediriger stdin ou stdout de/vers un fichier normal. Alors qu'auparavant stdin et stdout auraient été un tube - supporté par epoll très bien - il devient alors un fichier normal et epoll échoue bruyamment, cassant l'application.
Lors des tests dans mon entreprise, un problème avec epoll () est survenu, donc un coût unique par rapport à select.
Lorsque vous tentez de lire à partir du réseau avec un délai d'expiration, la création d'un epoll_fd (au lieu d'un FD_SET) et l'ajout du fd à epoll_fd sont beaucoup plus chers que la création d'un FD_SET (qui est un simple malloc).
Selon la réponse précédente, à mesure que le nombre de FD dans le processus devient important, le coût de select () augmente, mais dans nos tests, même avec des valeurs fd dans les 10 000, select était toujours un gagnant. Ce sont des cas où il n'y a qu'un seul fd sur lequel un thread attend et qui essaie simplement de surmonter le fait que la lecture et l'écriture réseau ne dépassent pas le délai lors de l'utilisation d'un modèle de thread bloquant. Bien sûr, les modèles de threads bloquants sont peu performants par rapport aux systèmes de réacteurs non bloquants, mais il y a des occasions où, pour s'intégrer à une base de code héritée particulière, il est nécessaire.
Ce type de cas d'utilisation est rare dans les applications hautes performances, car un modèle de réacteur n'a pas besoin de créer à chaque fois un nouveau epoll_fd. Pour le modèle où un epoll_fd a une longue durée de vie --- ce qui est clairement préféré pour toute conception de serveur haute performance --- epoll est clairement le gagnant à tous égards.