Les ordinateurs modernes ont plusieurs cœurs de traitement. En supposant qu'il y ait suffisamment de traitement pour que chaque cœur puisse rester occupé en permanence. ils se verront attribuer une file d'attente d'éléments de travail de calcul. Ou des threads à compléter par le planificateur.
Lors de l'exécution de ces threads, il est possible de générer de nouveaux threads ou éléments de travail. Ce sont des threads séparés qui peuvent être traités simultanément. Ils peuvent avoir besoin de renvoyer les résultats aux programmes de ponte ou de rester complètement séparés indéfiniment. En règle générale, ces threads enfants sont affectés au même cœur de traitement que le parent.
Tout cela suppose que tous les cœurs sont occupés. Cela se produira si aucun thread ne se termine ou si de nouveaux threads sont générés au même rythme ou plus rapidement que la fin des threads existants. Dans le monde réel, cependant, la charge de travail à long terme est rarement aussi simple, en particulier dans les appareils informatiques des utilisateurs finaux. Finalement, un noyau de traitement terminera probablement toutes les tâches assignées. Lorsque cela se produit, plutôt que de rester inactif et de gaspiller des performances potentielles, il vérifie à la place les files d'attente de travail des autres cœurs de traitement et leur vole un élément de travail.
Avantages et inconvénients
Le vol de travail signifie qu'un cœur de traitement inactif recherchera activement du travail à terminer. Cela empêche une fraction potentiellement importante du processeur global de rester inactive, ce qui est utile. Le vol de travail peut cependant entraîner des coûts. Par exemple, le nouveau cœur de traitement devra probablement charger toutes les données pertinentes dans sa mémoire cache.
Cela peut prendre du temps, surtout s'il doit être demandé à partir de la RAM système plutôt que d'être servi par un niveau de cache partagé. Il est possible que le processeur d'origine ait pu reprendre cet élément de travail dans ce délai, ce qui a conduit à une exécution globale plus rapide. Cela peut même être le cas si le cœur de traitement à partir duquel l'élément de travail a été volé n'a jamais commencé à le traiter. Certaines valeurs mises en cache peuvent être identiques entre les threads parent et enfant.
Implémentations
Plusieurs langages de programmation ont des runtimes qui peuvent planifier le travail directement sur des processeurs dédiés. Par exemple, le langage de programmation Cilk, le runtime Rust Tokio et la bibliothèque parallèle de tâches .Net peuvent le faire. Alternativement, le système d'exploitation peut être chargé de planifier le temps processeur réel. Avec le programme, il suffit d'ajouter des tâches à un pool de "threads de travail", qui sont eux-mêmes planifiés par le système d'exploitation.
Cela se produit dans les systèmes où le programme n'a pas d'accès direct dédié aux cœurs de traitement mais doit partager l'accès avec d'autres processus. Des précautions supplémentaires doivent être prises dans ce scénario pour s'assurer qu'un thread n'est pas volé à plusieurs reprises car il reste inactif.
Il existe différentes approches sur la manière dont les éléments de travail sont sélectionnés pour être volés. Dans le concept original, l'approche consistait à choisir un autre noyau aléatoire. S'il avait un ou plusieurs éléments de travail dans sa file d'attente, prenez le dernier. Selon la préférence pour savoir si un processus enfant est immédiatement exécuté par le processeur d'origine. Ou, s'il est poussé vers la file d'attente du processeur et que le processus parent continue d'être exécuté, le thread parent ou enfant sera volé.
Tout cela peut se résumer à Work Stealing, une technique d'équilibrage de charge qui garantit que la charge de mots est répartie uniformément entre les processeurs disponibles. De cette façon, tous les processeurs font quelque chose pour aider.
Conclusion
Le vol de travail est un processus qui se produit automatiquement dans les processeurs multicœurs. Chaque cœur a une file d'attente de tâches à effectuer. Lorsqu'un processeur termine ses tâches, il en vole une autre dans la file d'attente d'un autre cœur de traitement. Cela permet d'éviter que le processeur n'ait certains cœurs inactifs tandis que d'autres ont encore une file d'attente de tâches à effectuer.