Quelle est la différence entre un fil et une fibre? J'ai entendu parler de fibres de Ruby et j'ai lu qu'elles étaient disponibles dans d'autres langues, quelqu'un pourrait-il m'expliquer en termes simples quelle est la différence entre un fil et une fibre.
En termes plus simples, les fils sont généralement considérés comme préemptifs (bien que cela ne soit pas toujours vrai, selon le système d'exploitation), tandis que les fibres sont considérées comme des fils coopératifs légers. Les deux sont des chemins d'exécution distincts pour votre application.
Avec les threads: le chemin d'exécution en cours peut être interrompu ou préempté à tout moment (remarque: cette déclaration est une généralisation et peut ne pas toujours être vraie selon le système d'exploitation/package de threading/etc.). Cela signifie que pour les threads, l'intégrité des données est un gros problème car un thread peut être arrêté au milieu de la mise à jour d'un bloc de données, laissant l'intégrité des données dans un état incorrect ou incomplet. Cela signifie également que le système d'exploitation peut tirer parti de plusieurs processeurs et cœurs de processeur en exécutant plusieurs threads en même temps et en laissant le soin au développeur de protéger l'accès aux données.
Avec les fibres: le chemin d'exécution actuel n'est interrompu que lorsque la fibre cède l'exécution (même remarque que ci-dessus). Cela signifie que les fibres démarrent et s'arrêtent toujours à des endroits bien définis, de sorte que l'intégrité des données est beaucoup moins problématique. De plus, comme les fibres sont souvent gérées dans l'espace utilisateur, il n'est pas nécessaire d'effectuer des changements de contexte coûteux et des changements d'état du processeur, ce qui rend le passage d'une fibre à l'autre extrêmement efficace. D'un autre côté, comme deux fibres ne peuvent pas fonctionner exactement en même temps, le simple fait d'utiliser des fibres seules ne tirera pas parti de plusieurs processeurs ou de plusieurs cœurs de processeur.
Les threads utilisent la planification préemptive, tandis que les fibres utilisent la planification coopérative.
Avec un thread, le flux de contrôle peut être interrompu à tout moment et un autre thread peut prendre le relais. Avec plusieurs processeurs, vous pouvez avoir plusieurs threads s'exécutant tous en même temps ( multithreading simultané ou SMT). Par conséquent, vous devez faire très très attention à l'accès simultané aux données et protéger vos données avec des mutex, des sémaphores, des variables de condition, etc. Il est souvent très difficile de bien faire les choses.
Avec une fibre, le contrôle ne change que lorsque vous le lui dites, généralement avec un appel de fonction nommé quelque chose comme yield()
. Cela facilite l'accès simultané aux données, car vous n'avez pas à vous soucier de l'atomicité des structures de données ou des mutex. Tant que vous ne cédez pas, il n'y a aucun danger d'être préempté et d'avoir une autre fibre essayant de lire ou de modifier les données avec lesquelles vous travaillez. En conséquence, cependant, si votre fibre entre dans une boucle infinie, aucune autre fibre ne peut fonctionner, car vous ne cédez pas.
Vous pouvez également mélanger des fils et des fibres, ce qui pose les problèmes rencontrés par les deux. Non recommandé, mais cela peut parfois être la bonne chose à faire si cela est fait avec soin.
Dans Win32, une fibre est une sorte de thread géré par l'utilisateur. Une fibre a sa propre pile et son propre pointeur d'instructions, etc., mais les fibres ne sont pas planifiées par le système d'exploitation: vous devez appeler explicitement SwitchToFiber. Les threads, en revanche, sont planifiés de manière préventive par le système d'exploitation. Donc, en gros, une fibre est un thread qui est géré au niveau de l'application/du runtime plutôt que d'être un vrai thread du système d'exploitation.
Les conséquences sont que les fibres sont moins chères et que l'application a plus de contrôle sur la planification. Cela peut être important si l'application crée de nombreuses tâches simultanées et/ou souhaite optimiser étroitement leur exécution. Par exemple, un serveur de base de données peut choisir d'utiliser des fibres plutôt que des threads.
(Il peut y avoir d'autres utilisations pour le même terme; comme indiqué, il s'agit de la définition Win32.)
Tout d'abord, je recommanderais de lire cette explication de la différence entre les processus et les threads comme matériel de référence.
Une fois que vous avez lu que c'est assez simple. Les threads peuvent être implémentés dans le noyau, dans l'espace utilisateur, ou les deux peuvent être mélangés. Les fibres sont essentiellement des threads implémentés dans l'espace utilisateur.
Dans la section 11.4 "Processus et threads dans Windows Vista" dans les systèmes d'exploitation modernes, Tanenbaum commente:
Bien que les fibres soient programmées en coopération, s'il y a plusieurs threads programmant les fibres, une synchronisation minutieuse est nécessaire pour s'assurer que les fibres n'interfèrent pas entre elles. Pour simplifier l'interaction entre les threads et les fibres, il est souvent utile de créer uniquement autant de threads qu'il y a de processeurs pour les exécuter et d'affiner les threads à chaque exécution uniquement sur un ensemble distinct de processeurs disponibles, ou même sur un seul processeur. Chaque thread peut ensuite exécuter un sous-ensemble particulier des fibres, établissant une relation un à plusieurs entre les threads et les fibres, ce qui simplifie la synchronisation. Malgré cela, il existe encore de nombreuses difficultés avec les fibres. La plupart des bibliothèques Win32 ignorent complètement les fibres et les applications qui tentent d'utiliser des fibres comme s'il s'agissait de threads rencontreront diverses défaillances. Le noyau n'a aucune connaissance des fibres, et lorsqu'une fibre entre dans le noyau, le thread sur lequel il s'exécute peut se bloquer et le noyau planifiera un thread arbitraire sur le processeur, ce qui le rendra indisponible pour exécuter d'autres fibres. Pour ces raisons, les fibres sont rarement utilisées, sauf lors du portage de code à partir d'autres systèmes qui ont explicitement besoin des fonctionnalités fournies par les fibres.
Notez qu'en plus des threads et des fibres, Windows 7 introduit Planification en mode utilisateur :
La planification en mode utilisateur (UMS) est un mécanisme léger que les applications peuvent utiliser pour planifier leurs propres threads. Une application peut basculer entre les threads UMS en mode utilisateur sans impliquer l'ordonnanceur système et reprendre le contrôle du processeur si un thread UMS se bloque dans le noyau. Les threads UMS diffèrent des fibres en ce que chaque thread UMS a son propre contexte de thread au lieu de partager le contexte de thread d'un seul thread. La possibilité de basculer entre les threads en mode utilisateur rend UMS plus efficace que les pools de threads pour gérer un grand nombre d'éléments de travail de courte durée qui nécessitent peu d'appels système.
Pour plus d'informations sur les threads, les fibres et l'UMS, consultez Dave Probert: Inside Windows 7 - User Mode Scheduler (UMS) .
Les threads sont planifiés par le système d'exploitation (préventif). Un thread peut être arrêté ou repris à tout moment par l'OS, mais les fibres se gèrent plus ou moins elles-mêmes (coopératives) et se cèdent entre elles. C'est-à-dire que le programmeur contrôle quand les fibres effectuent leur traitement et quand ce traitement passe à une autre fibre.
Les threads ont été initialement créés en tant que processus légers. De façon similaire, les fibres sont un fil léger, reposant (de manière simplifiée) sur les fibres elles-mêmes pour se planifier les unes les autres, en donnant le contrôle.
Je suppose que la prochaine étape sera les brins où vous devrez leur envoyer un signal chaque fois que vous voulez qu'ils exécutent une instruction (un peu comme mon fils de 5 ans :-). Autrefois (et même maintenant sur certaines plates-formes embarquées), tous les threads étaient des fibres, il n'y avait pas de préemption et vous deviez écrire vos threads pour bien vous comporter.
Les threads s'appuient généralement sur le noyau pour interrompre le thread afin que celui-ci ou un autre thread puisse s'exécuter (ce qui est mieux connu sous le nom de multitâche préventif) tandis que les fibres utilisent le multitâche coopératif où c'est la fibre elle-même qui abandonne son temps de fonctionnement afin que d'autres fibres peuvent couler.
Voici quelques liens utiles qui l'expliquent mieux que moi:
La définition de fibre Win32 est en fait une définition de "fil vert" établie par Sun Microsystems. Il n'est pas nécessaire de gaspiller le terme fibre sur le thread d'une certaine sorte, c'est-à-dire un thread s'exécutant dans l'espace utilisateur sous le contrôle du code utilisateur/bibliothèque de threads.
Pour clarifier l'argument, regardez les commentaires suivants:
Nous devons supposer que les processus sont faits de fils et que les fils doivent être faits de fibres. Avec cette logique à l'esprit, l'utilisation de fibres pour d'autres types de fils est incorrecte.