Un'espressione in Verse può essere immediata o asincrona. Descrive il tempo che un'espressione può impiegare per essere valutata rispetto al ciclo di simulazione.
Pensa a un ciclo di simulazione come quando viene mostrato un nuovo frame.
Ci sono casi in cui possono verificarsi più cicli di simulazione prima di un nuovo frame, ad esempio se un gioco online non è sincronizzato con il server.
Immediato | espressione asincrona |
---|---|
Un'espressione immediata viene valutata senza ritardi, ovvero la valutazione viene completata entro il ciclo di simulazione corrente. | Un'espressione asincrona può richiedere tempo affinché venga valutata, ma non necessariamente. Un'espressione asincrona può essere completata nel ciclo di simulazione corrente o in uno successivo. |
Contesti asincroni
Le espressioni asincrone si possono utilizzare in qualsiasi codice Verse che ha un contesto asincrono.
Un contesto asincrono è il corpo di una funzione che ha lo specificatore effetto suspends. L'effetto suspends
indica che le funzioni espressione asincrona possono sospendere e trasferire in modo cooperativo il controllo ad altre espressioni concorrenti in vari punti di diversi cicli di simulazione prima che si completino.
La funzione OnBegin()
in un dispositivo Verse è una funzione asincrona comune utilizzata come punto di partenza per il codice asincrono.
La chiamata di una funzione espressione asincrona ha la stessa sintassi della chiamata di una funzione immediata:
OnBegin<override>()<suspends> : void =
HideAllPlatforms()
HideAllPlatforms()<suspends> : void =
for (Platform : Platforms):
Platform.Hide()
Sleep(Delay)
Come qualsiasi altra espressione, un'espressione asincrona può avere un risultato. Il risultato di un'espressione asincrona è disponibile solo quando è stato completato.
# 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}")
Qualsiasi blocco di codice che si trova all'interno di un contesto asincrono (all'interno del corpo di una funzione asincrona) può avere qualsiasi mix di espressioni immediate ed asincrone.
Se alcune espressioni in un blocco di codice sono asincrone, l'intero blocco di codice è considerato asincrono.
Se tutte le espressioni in un blocco di codice sono immediate, l'intero blocco di codice è considerato immediato.
Tutte le espressioni nell'esempio seguente sono espressioni asincrone, quindi il blocco di codice complessivo è asincrono:
Sleep(2.0) # waits 2 seconds
Boss.TauntEmote() # waits until TauntEmote() completes
Player.MoveToNearestNPC() # waits until MoveToNearestNPC() completes
Tutte le espressioni nell'esempio seguente sono espressioni immediate, quindi il blocco di codice complessivo è immediato:
Print("Reset after explosion")
Platform.Show()
set SecondsUntilExplosion = 12.0
Le espressioni nell'esempio seguente sono un mix di espressioni asincrone e immediate, quindi il blocco di codice complessivo è asincrono:
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
Le espressioni immediate si uniscono da sole. Tutte le espressioni adiacenti immediate (non asincrone) sono considerate atomiche: è garantito che il loro codice venga eseguito senza interruzioni nello stesso aggiornamento e senza prelazione o commutazione di contesto. È come se tale codice fosse circondato da una primitiva di esclusione automatica reciproca .
Quindi, dall'esempio di codice precedente, queste espressioni immediate sono trattate in modo atomico:
# 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
Come ogni altro blocco di codice, l'ultimo blocco di codice asincrono viene utilizzato come risultato.
Espressioni di concorrenza
Verse utilizza espressioni di concorrenza per determinare se le espressioni vengono eseguite contemporaneamente (allo stesso tempo) o in sequenza, una dopo l'altra. Un'espressione asincrona viene eseguita o richiamata nel tempo, quindi queste espressioni di concorrenza possono essere particolarmente utili quando si utilizzano espressioni asincrone.
Concorrenza strutturata
Un'espressione asincrona bloccherà l'esecuzione di altre espressioni se richiede molto tempo per essere eseguita. Ad esempio, utilizzando Sleep(90.0)
farà sì che il programma attenda 90 secondi, bloccando l'espressione successiva fino a quando Sleep(90.0)
non viene eseguita completamente.
Le espressioni di concorrenza strutturata vengono utilizzate per specificare il flusso temporale logico asincrono e per modificare la natura bloccante delle espressioni asincrone con una durata vincolata logicamente a uno specifico ambito del contesto asincrono (come ad esempio un corpo di funzione asincrona).
Questo è simile al flusso di controllo strutturato, come block
, if
, for
e loop
che vincola al relativo ambito.
Per ulteriori informazioni sulla concorrenza strutturata, vedi Sync, Race, Rush e Branch.
Concorrenza non strutturata
Esiste solo un'espressione di concorrenza non strutturata: spawn. Questa espressione ha una durata di vita che non è logicamente vincolata a uno specifico ambito di contesto asincrona, ma che potenzialmente può estendersi oltre l'ambito in cui è stata eseguita.
Concorrenza non strutturata è come una via di fuga di emergenza: non dovresti usarla regolarmente, anche se a volte è la tua migliore e unica opzione.
Le espressioni di concorrenza strutturata (sync
, race
, rush
e branch
) devono essere utilizzate prima delle espressioni di concorrenza non strutturata (generare
) ove possibile.
Per ulteriori informazioni sulla concorrenza non strutturata, vedi Spawn.
Task per il tracciamento delle espressioni asincrone in esecuzione
Un'espressione asincrona ha un task associato.
Un task è un oggetto che rappresenta una funzione espressione asincrona che ha iniziato a essere eseguita, ma è stata sospesa per permettere il completamento di un altro task.
Il task può essere utilizzato per controllare lo stato di un'espressione asincrona e per annullare l'espressione asincrona, se lo si desidera.
Per maggiori informazioni sui task, vedi Task.