Une expression dans Verse peut être immédiate ou asynchrone. Il s'agit du temps que met une expression pour s'évaluer par rapport aux mises à jour de simulation.
Considérez la mise à jour d'une simulation comme le moment où une nouvelle image s'affiche.
Dans certains cas, plusieurs mises à jour de simulation peuvent se produire avant une nouvelle image, par exemple si un jeu en ligne n'est plus synchronisé avec le serveur.
| immediate (immédiate) | async (asynchrone) |
|---|---|
Une expression immédiate s'évalue sans délai, ce qui signifie que l'évaluation sera terminée dans la mise à jour de la simulation actuelle. | Une expression asynchrone a la possibilité de prendre du temps pour s'évaluer, mais ne doit pas nécessairement le faire. Une expression asynchrone peut se terminer ou non lors de la mise à jour actuelle de la simulation ou lors d'une mise à jour ultérieure. |
Contextes asynchrones
Les expressions asynchrones peuvent être utilisées dans tout code Verse doté d'un contexte asynchrone.
Un contexte asynchrone est le corps d'une fonction qui a le spécificateur d'effet de suspension. L'effet suspends indique que les fonctions asynchrones peuvent suspendre et transférer de manière coopérative le contrôle à d'autres expressions concurrentes à divers moments au cours de plusieurs mises à jour de simulation avant de se terminer.
La fonction OnBegin() dans un appareil Verse est une fonction asynchrone commune utilisée comme point de départ du code asynchrone.
La syntaxe d'appel d'une fonction asynchrone est la même que celle d'une fonction immédiate :
OnBegin<override>()<suspends> : void =
HideAllPlatforms()
HideAllPlatforms()<suspends> : void =
for (Platform : Platforms):
Platform.Hide()
Sleep(Delay)Comme toute autre expression, une expression asynchrone peut avoir un résultat. Le résultat d'une expression asynchrone est seulement disponible une fois qu'elle est terminée.
# Npc is undefined until it is bound after MoveToNearestNPC() completes which may be several frames into the future
Npc := Player.MoveToNearestNPC()
#Only called after MoveToNearestNPC() completes
Print("Moved to {Npc}")Tout bloc de code qui se trouve dans un contexte asynchrone (à l'intérieur du corps d'une fonction asynchrone) peut avoir n'importe quel mélange d'expressions immédiates et asynchrones.
Si toutes les expressions d'un bloc de code sont asynchrones, alors l'ensemble du bloc de code est considéré comme étant asynchrone.
Si toutes les expressions d'un bloc de code sont immédiates, alors l'ensemble du bloc de code est considéré comme immédiat.
Dans l’exemple ci-dessous, toutes les expressions sont asynchrones ; l’ensemble du bloc de code est donc asynchrone :
Sleep(2.0) # waits 2 seconds
Boss.TauntEmote() # waits until TauntEmote() completes
Player.MoveToNearestNPC() # waits until MoveToNearestNPC() completesDans l’exemple ci-dessous, toutes les expressions sont immédiates ; l’ensemble du bloc de code est donc immédiat :
Print("Reset after explosion")
Platform.Show()
set SecondsUntilExplosion = 12.0Dans l’exemple ci-dessous, toutes les expressions sont un mélange d’immédiates et d’asynchrones ; l’ensemble du bloc de code est donc asynchrone :
Print("Started")
var Seconds := 1.0
Sleep(Seconds)
Print("Waited {Second} seconds")
set Second += 1.0
Sleep(Seconds)
Print("Waited {Second} seconds")
set Second += 1.0
Les expressions immédiates restent ensemble naturellement. Toutes les expressions immédiates adjacentes (non asynchrones) sont considérées comme atomiques : leur code est sûr de s'exécuter sans interruption dans la même mise à jour et sans préemption ni changement de contexte. C'est comme si ces codes étaient enveloppés d'une exclusion mutuelle primitive automatique.
Ainsi, dans le code ci-dessus, ces expressions immédiates sont traitées de manière atomique :
# These two expressions are always kept together
Print("Started")
var Seconds := 1.0
Sleep(Seconds)
# These two expressions are always kept together
Print("Waited {Second} seconds")
set Second += 1.0
Comme tout autre bloc de code, la dernière expression d'un bloc de code asynchrone est utilisée comme résultat.
Expressions de simultanéité
Verse utilise des expressions de simultanéité pour déterminer si les expressions s'exécutent de manière simultanée (au même moment) ou en séquence, l'une après l'autre. Une expression asynchrone est exécutée ou appelée dans le temps, ces expressions de simultanéité peuvent donc être très utiles lorsque vous utilisez des expressions asynchrones.
Simultanéité structurée
Une expression asynchrone empêchera l’exécution des autres expressions si elles prennent du temps. Par exemple, l'utilisation de Sleep(90.0) entraîne un arrêt du système de 90 secondes, empêchant la prochaine expression de s'exécuter jusqu'à la fin de Sleep(90.0).
Les expressions de simultanéité structurée sont utilisées pour spécifier le flux temporel logique asynchrone et modifier la nature bloquante des expressions asynchrones dont la durée de vie est logiquement limitée à une étendue de contexte asynchrone spécifique (tel qu'un corps de fonction asynchrone).
Cela s'apparente à un contrôle de flux structuré tel que block, if, for et loop qui reste contraint à l'étendue associée.
Les expressions asynchrones de Verse n'utilisent pas les primitives yield et await auxquelles les implémentations asynchrones ont recours dans d'autres langages. Les mêmes mécanismes sont réalisés en utilisant les expressions de simultanéité de Verse et les mécanismes internes.
Pour en savoir plus sur la simultanéité structurée, consultez les rubriques Synchroniser, Course, Ruée et Branche.
Simultanéité non structurée
Il n'existe qu'une seule expression de simultanéité non structurée : spawn. Cette expression a une durée de vie qui n'est pas logiquement limitée à une étendue de contexte asynchrone spécifique, mais peut s'étendre au-delà de celle où elle a été exécutée.
La simultanéité non structurée est comme une sortie de secours - vous ne devriez pas l'utiliser régulièrement, mais parfois c'est votre seul choix et vous serez heureux qu'elle existe.
Privilégiez les expressions de simultanéité structurée (sync, race, rush et branch) aux expressions de simultanéité non structurées (spawn) chaque fois que cela est possible.
Pour en savoir plus sur la simultanéité non structurée, consultez la rubrique Spawn.
Tâches pour le suivi du site qui exécute actuellement les expressions asynchrones
Une expression asynchrone a une tâche qui lui est associée.
Une tâche est un objet qui représente une fonction asynchrone en cours d'exécution, mais qui a été suspendue pour permettre à une autre tâche de se terminer.
La tâche peut être utilisée pour vérifier le statut d’une expression asynchrone et pour l’annuler.
Pour en savoir plus sur les tâches, consultez la rubrique Tâche.