Una expresión en Verse puede ser inmediata o asíncrona. Describe el tiempo que puede tardar una expresión en evaluar en relación con actualizaciones de simulación.
Considera una actualización de simulación como el punto donde se muestra un nuevo fotograma.
Hay casos en los que múltiples actualizaciones de simulación pueden producirse antes de un nuevo fotograma, como si un juego en línea se desincroniza con el servidor.
| inmediata | asíncrona |
|---|---|
Una expresión inmediata se evalúa sin demora, lo que significa que la evaluación se completará en la actualización de simulación actual. | Una expresión asíncrona tiene la posibilidad de tomar tiempo para evaluar, pero no necesariamente debe hacerlo. Una expresión asíncrona puede o no completarse en la actualización de simulación actual o en una posterior. |
Contextos asíncronos
Las expresiones asíncronas se pueden usar en cualquier código de Verse que tenga un contexto asíncrono.
Un contexto asíncrono es el cuerpo de una función que tiene el especificador de efecto suspends. El efecto suspends indica que las funciones asíncronas pueden suspender y transferir el control de manera cooperativa a otras expresiones concurrentes en varios puntos durante varias actualizaciones de simulación antes de que se completen.
OnBegin() es una función asíncrona común utilizada como punto de partida para el código asíncrono.
Llamar a una función asíncrona tiene la misma sintaxis que llamar a una función inmediata:
OnBegin<override>()<suspends> : void =
HideAllPlatforms()
HideAllPlatforms()<suspends> : void =
for (Platform : Platforms):
Platform.Hide()
Sleep(Delay)Al igual que cualquier expresión, las expresiones asíncronas pueden tener resultados. El resultado de una expresión asíncrona solo está disponible una vez que se completó.
# 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}")Cualquier bloque de código que esté dentro de un contexto asíncrono (dentro del cuerpo de una función asíncrona) puede tener cualquier mezcla de expresiones inmediatas y asíncronas.
Si cualquiera de las expresiones de un bloque de código es asíncrona, se considera que todo el bloque de código es asíncrono.
Si todas las expresiones de un bloque de código son inmediatas, se considera que todo el bloque de código es inmediato.
Todas las expresiones en el siguiente ejemplo son asíncronas, de manera que el bloque de código general es asíncrono:
Sleep(2.0) # waits 2 seconds
Boss.TauntEmote() # waits until TauntEmote() completes
Player.MoveToNearestNPC() # waits until MoveToNearestNPC() completesTodas las expresiones en el siguiente ejemplo son inmediatas, de manera que el bloque de código general es inmediato:
Print("Reset after explosion")
Platform.Show()
set SecondsUntilExplosion = 12.0Todas las expresiones en el siguiente ejemplo son una mezcla de asíncrona e inmediata, de manera que el bloque de código general es asíncrono:
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
Las expresiones inmediatas permanecen unidas por sí mismas. Todas las expresiones inmediatas adyacentes (no asíncronas) se consideran atómicas: se garantiza que su código se ejecutará sin interrupción dentro de la misma actualización y sin preferencia o cambio de contexto. Es como si dicho código tuviera una exclusión mutua primitiva envuelta alrededor de ellos.
Así que desde el código anterior, estas expresiones inmediatas se tratan atómicamente:
# 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
Como cualquier otro bloque de código, se utiliza como resultado la última expresión en un bloque de código asíncrono.
Expresiones de concurrencia
Verse usa expresiones de concurrencia para determinar si las expresiones ejecutan simultáneamente (al mismo tiempo), o en secuencia, uno tras otro. Una expresión asíncrona se ejecuta o invoca con el tiempo, por lo que estas expresiones de concurrencia pueden ser especialmente útiles cuando usas expresiones asíncronas.
Concurrencia estructurada
Una expresión asíncrona bloqueará la ejecución de otras expresiones si tarda mucho tiempo en ejecutarse. Por ejemplo, usar Sleep(90.0) hará que el programa espere 90 segundos, y bloqueará la siguiente expresión hasta que Sleep(90.0) se ejecute por completo.
Las expresiones de concurrencia estructurada se utilizan para especificar un flujo de tiempo lógico asíncrono y para modificar la naturaleza de bloqueo de las expresiones asíncronas con una vida útil restringida lógicamente a un ámbito de contexto asíncrono específico (como el cuerpo de una función asíncrona).
Esto es similar al control de flujo estructurado como block, if, for y loop que se restringen a sus ámbitos asociados.
Las expresiones asíncronas de Verse no usan las primitivas yield y await que usan las implementaciones asíncronas en otros lenguajes. Se logran los mismos mecanismos utilizando las expresiones de concurrencia de Verse y los mecanismos internos.
Para obtener más información sobre la concurrencia estructurada, consulta Sync, Race, Rush y Branch.
Concurrencia no estructurada
Solo hay una expresión de concurrencia no estructurada: spawn. Esta expresión tiene una duración que no está restringida lógicamente a un ámbito de contexto asíncrono específico, pero que potencialmente puede extenderse más allá del ámbito en el que se ejecutó.
La concurrencia no estructurada es como una escotilla de escape de emergencia: no deberías usarla de forma regular aunque a veces es tu única opción y te alegrarás de que esté ahí.
Las expresiones de concurrencia estructurada (sync, race, rush y branch) deben preferirse a la simultaneidad no estructurada (spawn) siempre que sea posible.
Para obtener más información sobre la concurrencia no estructurada, consulta Spawn.
Tareas para el seguimiento de las expresiones asíncronas que se ejecutan actualmente
Una expresión asíncrona tiene una tarea asociada.
Una tarea es un objeto que representa una función asíncrona que comenzó a ejecutarse, pero se suspendió para permitir que otra tarea se complete.
La tarea se puede utilizar para comprobar el estado de una expresión asíncrona y para cancelar la expresión asíncrona, si se desea.
Para obtener más información sobre las tareas, consulta Tarea.