- Le langage Zig introduit un nouveau modèle basé sur l’interface
Io pour réduire la complexité du design asynchrone d’I/O existant
- Ce modèle conserve une structure de fonction identique sans distinguer code synchrone et asynchrone, et propose deux implémentations :
Io.Threaded et Io.Evented
Io.Threaded exécute par défaut de manière synchrone, tandis que Io.Evented exécute en mode asynchrone basé sur une boucle d’événements
- Les développeurs peuvent contrôler l’exécution parallèle via
async() et concurrent(), avec une optimisation des performances possible sans modifier le code
- Cette approche résout le problème de la coloration de fonctions et vise à préserver la simplicité et le contrôle de Zig tout en offrant de hautes performances asynchrones
Évolution de la conception asynchrone de Zig
- Zig, estimant que l’ancien modèle asynchrone ne s’accordait pas bien avec sa philosophie de minimalisme, a recherché une nouvelle approche
- L’ancien modèle avait une faible intégration avec le reste des fonctionnalités
- Le nouveau modèle permet de gérer l’I/O synchrone et asynchrone avec la même structure de code
- Le nouveau modèle est centré sur une interface générique
Io
- Toutes les fonctions d’I/O reçoivent une instance
Io en paramètre pour s’exécuter
- À l’image de l’interface
Allocator, il permet de piloter l’I/O de la même manière que l’allocation mémoire
Structure de l’interface Io
- La bibliothèque standard inclut deux implémentations de base
Io.Threaded : exécution synchrone par défaut, avec traitement parallèle par threads si nécessaire
Io.Evented : exécution asynchrone basée sur une boucle d’événements (io_uring, kqueue, etc.)
- Les utilisateurs peuvent écrire de nouvelles implémentations
Io, pour un contrôle fin du mode d’exécution
Exemple de code et fonctionnement
- La fonction d’exemple
saveFile() crée, écrit et ferme un fichier
- Avec
Io.Threaded, elle s’exécute avec des appels système classiques
- Avec
Io.Evented, elle s’exécute via un backend asynchrone
- Dans les deux cas,
writeAll() garantit que l’opération est terminée au moment de son appel
- Le même code fonctionne de la même manière dans les contextes synchrone et asynchrone
- Les auteurs de bibliothèques n’ont pas à se soucier du mode d’exécution
Exécution parallèle et async() / concurrent()
- La fonction
async() demande une exécution asynchrone, mais avec Io.Threaded, elle peut s’exécuter immédiatement
- Avec
Io.Evented, il est possible de sauvegarder deux fichiers en parallèle avec une exécution réellement asynchrone
- La fonction
concurrent() est utilisée lorsque une exécution réellement parallèle est nécessaire
Io.Threaded utilise un pool de threads
Io.Evented fonctionne de la même manière que async()
- Un mauvais choix de fonction (
async au lieu de concurrent) est considéré comme un bug et ne peut pas être empêché au niveau du langage
Style de code et intégration au langage
- Sans syntaxe dédiée à l’asynchrone, le style de code Zig standard est conservé
- Les structures de contrôle existantes comme
try, defer sont utilisées telles quelles
- Andrew Kelley a indiqué que « cela se lit comme du code Zig standard »
- Un exemple de résolution DNS asynchrone est présenté
- Contrairement à
getaddrinfo(), il ne renvoie que la première réponse réussie et annule les autres requêtes
Planification future et état d’avancement
Io.Evented est encore en phase expérimentale, avec un support incomplet sur certains systèmes d’exploitation
- Une implémentation
Io compatible WebAssembly est prévue, et un travail fonctionnel correspondant reste à effectuer
- Il existe 24 tâches de suivi liées à
Io, dont la majorité sont encore incomplètes
- Zig n’étant pas encore en version 1.0, l’I/O asynchrone et la génération de code natif restent des chantiers majeurs
- Ce modèle devrait permettre de réduire la fréquence de réécriture du code causée par des changements dans l’interface I/O
Synthèse des discussions communautaires
- Plusieurs commentaires jugent l’approche de Zig plus simple et plus flexible que le modèle
async/await de Rust
- Rust devient plus complexe en combinant plusieurs executors
- Zig permet la coexistence de plusieurs executors grâce à l’interface
Io
- Certains soulignent que le code peut devenir un peu verbeux
- Mais une API explicite améliore la sécurité, les performances et le contrôle des tests
- Les discussions techniques ont aussi abordé la différence entre exécution asynchrone et exécution thread, ainsi que les implémentations de coroutines stackful et stackless
- L’
Io de Zig est implémenté sous forme d’extension de la bibliothèque standard, sans traitement spécial au niveau du langage
- Une implémentation de coroutine stackless est prévue à l’avenir
Conclusion
- Le nouveau modèle asynchrone de Zig vise à concilier la simplicité du langage et les performances I/O élevées
- En résolvant le problème de la coloration de fonctions, en intégrant code synchrone et asynchrone, et grâce à une structure de contrôle explicite, il est considéré comme une étape clé vers la stabilisation de Zig 1.0
Aucun commentaire pour le moment.