1 points par GN⁺ 2023-10-08 | 1 commentaires | Partager sur WhatsApp
  • Cet article traite de la controverse, dans la communauté Rust, autour de l’usage des exécuteurs multithread, c’est-à-dire des runtimes async qui pratiquent le work-stealing pour répartir les tâches de manière équilibrée.
  • Certains utilisateurs de Rust défendent une architecture alternative appelée « thread-per-core », qui promet de meilleures performances et une implémentation plus simple.
  • Le terme « thread-per-core » est trompeur. Tous les exécuteurs multithread sont de type thread-per-core : ils créent un thread OS par cœur et planifient les tâches sur ces threads.
  • Le thread-per-core combine trois idées : gérer la concurrence en espace utilisateur, rendre les E/S asynchrones pour éviter de bloquer les threads, et partitionner les données entre les cœurs CPU afin d’éliminer les coûts de synchronisation et les déplacements de données entre caches CPU.
  • La controverse porte surtout sur le troisième point, et l’async Rust permet de satisfaire les deux premières exigences.
  • Dans une architecture thread-per-core, deux optimisations sont possibles : voler le travail entre threads et partager aussi peu d’état que possible.
  • Le work-stealing améliore la tail latency en permettant à tous les threads de toujours avoir du travail, mais il est difficile à implémenter et peut entraîner des coûts de synchronisation ainsi que des défauts de cache.
  • Le share-nothing améliore la tail latency en conservant les données dans les caches plus rapides associés à un seul cœur CPU, mais il peut être difficile à mettre en œuvre pour des applications complexes qui doivent modifier l’état sur plusieurs partitions.
  • L’article suggère que, dans les systèmes utilisant un état partagé, le work-stealing pourrait améliorer l’utilisation du CPU sous charge.

1 commentaires

 
GN⁺ 2023-10-08
Avis Hacker News
  • Le cœur du débat n’est pas les exécuteurs avec vol de tâches par cœur, mais de savoir si async/await est une bonne abstraction en Rust.
  • Le modèle thread-per-core a été inventé pour résoudre les problèmes de scalabilité et d’efficacité du calcul sur les serveurs génériques à grand nombre de cœurs, et il s’est révélé excellent pour les charges I/O-bound à haut débit.
  • L’architecture thread-per-core est là pour rester grâce à sa scalabilité et à son efficacité, mais la plupart des ingénieurs logiciel ont une intuition limitée de ce à quoi ressemble un design thread-per-core moderne et idiomatique.
  • Certaines applications sont mieux adaptées à des systèmes monothread, et Rust permet cette flexibilité.
  • Il existe des critiques de la programmation async en Rust, notamment l’exigence de Send + Sync + 'static, que certains jugent contraignante.
  • La contrainte Send est une exigence qui permet de déplacer des tâches entre les threads de l’exécuteur, ce qui semble être un défaut du système async de Rust.
  • Il n’existe pas d’approche universelle permettant d’obtenir les meilleures performances pour tous les programmes, et l’usage de async est considéré comme une optimisation prématurée pour beaucoup de programmes Rust.
  • Les changements de contexte du noyau étant coûteux, on préfère les designs thread-per-core, mais l’ordonnancement par changement de contexte en espace utilisateur peut aussi poser problème.
  • Le vol de tâches est une manière de traiter la latence en queue, mais il entraîne des défauts de cache et des contraintes supplémentaires pour les développeurs, comme Send, Sync et ‘static.