Выражение в Verse может быть как непосредственным, так и асинхронным. Этот параметр описывает время, которое может потребоваться выражению для оценки относительно обновлений симуляции.
Обновление симуляции можно представить как отображение нового кадра.
Иногда перед новым кадром может произойти несколько обновлений симуляции, например когда онлайн-игра перестаёт синхронизироваться с сервером.
непосредственный (immediate) | async |
---|---|
Непосредственное выражение рассчитывается без задержки, то есть оценка завершается в течение текущего обновления симуляции. | Для расчёта асинхронного выражения иногда требуется время. Это выражение может завершиться/не завершиться в текущем обновлении симуляции или завершиться в более позднем обновлении. |
Асинхронные контексты
Асинхронные выражения можно использовать в любом коде Verse, где есть асинхронный контекст.
Асинхронный контекст — это тело функции, имеющей спецификатор эффекта suspends. Эффект suspends
указывает на то, что асинхронные функции могут приостанавливать и совместно передавать управление другим одновременным выражениям в течение нескольких обновлений симуляции до их завершения.
Функция OnBegin()
в устройстве Verse — это обычная асинхронная функция, используемая в качестве отправной точки для асинхронного кода.
Вызов асинхронной функции имеет тот же синтаксис, что и вызов текущей функции:
OnBegin<override>()<suspends> : void =
HideAllPlatforms()
HideAllPlatforms()<suspends> : void =
for (Platform : Platforms):
Platform.Hide()
Sleep(Delay)
Как и любое другое выражение, асинхронное выражение может иметь результат. Асинхронное выражение выдаёт результат только после завершения.
# 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}")
Любой блок кода, находящийся в асинхронном контексте (внутри тела асинхронной функции), может содержать любое сочетание непосредственных выражений и асинхронных выражений.
Если какие-либо выражения в блоке кода являются асинхронными, то весь блок кода считается асинхронным.
Если все выражения в блоке кода являются непосредственными выражениями, то весь блок кода считается непосредственным.
Все выражения в приведённом ниже примере являются асинхронными, поэтому весь блок кода в целом является асинхронным:
Sleep(2.0) # waits 2 seconds
Boss.TauntEmote() # waits until TauntEmote() completes
Player.MoveToNearestNPC() # waits until MoveToNearestNPC() completes
Все выражения в приведённом ниже примере являются непосредственными, поэтому весь блок кода в целом является непосредственным:
Print("Reset after explosion")
Platform.Show()
set SecondsUntilExplosion = 12.0
Выражения в приведённом ниже примере представляют собой комбинацию асинхронных и непосредственных выражений, поэтому блок кода в целом является асинхронным:
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
Непосредственные выражения выполняются по очереди сами по себе. Все смежные непосредственные (не асинхронные) выражения считаются атомарными — их код гарантированно выполняется без прерывания в одном обновлении без вытеснения или переключения контекста. Это похоже на то, как если бы такой код был упакован в примитив с функцией автоматического взаимного исключения.
В примере кода выше эти непосредственные выражения обрабатываются атомарно:
# 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
Как и в любом другом блоке кода, в качестве результата используется последнее выражение в асинхронном блоке кода.
Выражения с одновременным выполнением
В Verse используются выражения с одновременным выполнением, чтобы определить, как будут выполняться выражения: конкурентно (одновременно) или последовательно (одно за другим). Асинхронное выражение выполняется или вызывается постепенно, поэтому непосредственные выражения могут быть пригодиться при использовании асинхронных выражений.
Структурированное одновременное выполнение
Асинхронное выражение блокирует выполнение других выражений, если его выполнение занимает много времени. Например, использование Sleep(90.0)
заставит программу ждать 90 секунд, блокируя выполнение следующего выражения до полного выполнения Sleep(90.0)
.
Выражения со структурированным одновременным выполнением используются для реализации асинхронного логического выполнения и для изменения блочного характера асинхронных выражений при помощи срока жизни, ограничивающегося определённой областью асинхронного контекста (например, телом асинхронной функции).
Это похоже на структурированный контроль исполнения, реализуемый с помощью выражений block
, if
, for
и loop
, которые ограничены связанной с ними областью видимости.
В асинхронных выражениях Verse не используются примитивы yield
и await
, используемые в асинхронных реализациях в других языках. Эти же механизмы реализуются с помощью выражений с одновременным выполнением и внутренних устройств Verse.
Подробнее о структурированном одновременном выполнении см. в разделах Sync, Race, Rush и Branch.
Неструктурированное одновременное выполнение
Существует только одно выражение c неструктурированным одновременным выполнением — spawn. Это выражение имеет срок жизни, который логически не ограничен определённой областью видимости асинхронного контекста, но который потенциально может выходить за пределы области видимости, в которой оно выполнялось.
Неструктурированное одновременное выполнение является исключительным решением — не следует использовать его на регулярной основе, хотя иногда оно является лучшим и единственным способом.
Выражения со структурированным одновременным выполнением (sync
, race
, rush
и branch
) по возможности должны использоваться перед выражениями с неструктурированным одновременным выполнением (spawn
).
Более подробно о неструктурированном одновременном выполнении рассказано в разделе Spawn.
Задачи по отслеживанию текущих асинхронных выражений
Для асинхронного выражения предусмотрена связанная с ним задача.
Задача — это объект, представляющий асинхронную функцию, которая начала выполняться, но была приостановлена, чтобы можно было завершить другую задачу.
Эту задачу можно использовать для проверки статуса асинхронного выражения и его отмены при необходимости.
Более подробную информацию о задачах можно найти в разделе Задача.