Introduction

Lors de l'ajout de la prise en charge de l'exécution asynchrone à notre bibliothèque Python de durabilité, nous avons rencontré un défi fondamental : les flux de travail durables doivent être déterministes pour permettre une récupération basée sur le replay.

Contexte Technique

Les flux de travail asynchrones Python sont souvent exécutés de manière concurrente, ce qui rend difficile la définition d'un ordre d'exécution déterministe. L'utilisation d'asyncio.gather pour collecter les résultats de plusieurs étapes exécutées de manière concurrente est courante, mais cela introduit des problèmes d'ordre d'exécution.

Le problème est que la concurrence introduit un ordre d'exécution non évident. Lorsque plusieurs tâches s'exécutent en même temps, l'ordre exact d'exécution peut varier. Cependant, lors de la récupération, le flux de travail doit être en mesure de rejouer ces étapes de manière déterministe, en récupérant les étapes terminées à partir de points de contrôle et en réexécutant les étapes incomplètes.

Analyse et Implications

La compréhension de la façon dont fonctionne réellement la boucle d'événements asynchrone Python est essentielle. La boucle d'événements est un thread unique qui exécute une file d'attente de tâches. Lorsque vous appelez une fonction asynchrone, elle ne s'exécute pas réellement ; au lieu de cela, elle crée une « coroutine », un appel de fonction gelé qui n'est pas exécuté.

La création d'une tâche asynchrone à l'aide d'asyncio.create_task ou asyncio.gather permet de planifier l'exécution de la fonction asynchrone. La boucle d'événements exécute les tâches de manière séquentielle, en les faisant céder le contrôle lorsqu'elles attendent une opération qui n'est pas prête.

Perspective

En comprenant comment fonctionne la boucle d'événements asynchrone Python, nous pouvons créer des flux de travail déterministes qui peuvent être exécutés de manière concurrente. Cela nécessite de placer du code avant la première attente d'une étape pour attribuer un ID d'étape de manière déterministe. Cela garantit que les tâches de traitement des étapes sont exécutées dans l'ordre exact dans lequel elles sont passées à asyncio.gather.