Асинхронные функции¶
Асинхронные функции - это корутины, которые возвращают одно значение.
Объявляются они с использованием ключевого слова async
.
Возвращают значение асинхронные функции так же, как и обычные - через оператор return
.
Правила его использования такие же, как и в обычных функциях.
Пример простейшей асинхронной функции:
fn async DoubleIt(u32 x) : u32
{
return x * 2u;
}
В асинхронных функциях можно использовать оператор yield
без значения.
Его использование приостанавливает выполнение асинхронной функции, которое может быть далее продолжено с кода, следующего после yield
.
Использование асинхронных функций¶
Вызов асинхронной функции возвращает значение объекта-асинхронной функции. Запустить/возобновить выполнение асинхронной функции и получить результат можно с использованием оператора if_coro_advance для этого объекта.
Каждое использование этого оператора возобновляет выполнение асинхронной функции, если только она уже не завершилась.
Блоку внутри if_coro_advance
управление может передаться лишь однажды - когда асинхронная функция завершилась и тем самым вернула результат.
// Данная асинхронная функция делает несколько остановок, прежде чем вернуть результат.
fn async SimpleFunc() : i32
{
yield;
yield;
yield;
return 555444;
}
fn Foo()
{
auto mut f= SimpleFunc();
auto mut result= 0;
// Выполняем оператор if_coro_advance до тех пор, пока асинхронная функция не завершится.
// Будет выполнено 3 полных итерации цикла (по числу yield операторов в асинхронной функции), на 4-й итерации произойдёт выход из цикла.
loop
{
if_coro_advance( x : f )
{
result= x;
break;
}
}
}
Стоит быть внимательным с использованием if_coro_advance
в цикле до получения результата.
Если объект асинхронной функции уже ранее завершился, if_coro_advance
уже никогда не вернёт результат, и тем самым цикл может быть бесконечным.
Чтобы такого избежать, стоит проверять корутины на завершённость, прежде чем входить в цикл с if_coro_advance
.
оператор await¶
Для упрощения вызова асинхронных функций существует также оператор await
.
Этот оператор является постфиксным, состоит из точки (.
) и ключевого слова await
и может быть использован для объекта-асинхронной функции внутри другой асинхронной функции.
Данный оператор работает следующим образом: он возобновляет выполнение асинхронной функции, если она завершилась - извлекается результат, иначе вызывающая асинхронная функция приостанавливается и управление после её возобновления будет передано коду, который снова возобновляет выполнение переданной асинхронной функции и т. д. пока выполнение переданной асинхронной функции не завершится.
Во многом этот оператор эквивалентен следующему коду:
loop
{
if_coro_advance( x : f )
{
// x - результат оператора await.
break;
}
else
{
yield;
}
}
Оператор await
требует, чтобы переданное значение было непосредственным значением типа объекта-асинхронной функции.
Также необходимо, чтобы переданная асинхронная функция ещё не завершилась, иначе произойдёт halt
.
После извлечения результата значение асинхронной функции разрушается должным образом.
Пример использования оператора await
:
fn async Foo( i32 x ) : i32;
fn async Bar( i32 x, i32 y ) : i32
{
auto foo_res= Foo( x * y ).await;
return foo_res / 3;
}
По сути оператор await
является способом упрощения вызова одной асинхронной функции из другой.
Там, где для обычных функций просто используется оператор вызова, для асинхронных функций используется оператор вызова с последующим оператором await
.
Тип асинхронной функции¶
Тип асинхронной функции - это тип объекта-асинхронной функции. Асинхронные функции возвращают объекты типа асинхронных функций.
В Ü существует специальный синтаксис для указания типа асинхронной функции.
Состоит он из ключевого слова async
, опциональной нотации для указания внутренних ссылок, опционального non_sync
тега, типа (с учётом ссылочности) возвращаемого значения.
type IntAsyncFunc= async : i32; // Простейшая асинхронная функция
var [ [ char8, 2 ], 1 ] return_references[ "0a" ];
type FloatRefAsyncFunc= async'imut' : f32 & @(return_references); // Асинхронная функция, возвращающая ссылку и хранящая внутри себя ссылки.
type NonSyncRefAsyncFunc= async'mut' non_sync : u64 &mut @(return_references); // non_sync асинхронная функция, возвращающая изменяемую ссылку и хранящая внутри себя изменяемые ссылки.
Как можно заметить, тип объекта-асинхронной функции не определяется конкретными особенностями конкретной асинхронной функции (как она была создана). Это позволяет использовать одну и ту же переменную для хранения объектов-асинхронных функций, порождённых разными асинхронными функциями с разным телом и разными параметрами.
// Асинхронные функции. Тип их возвращаемого значения - (async : i32).
fn async Foo(i32 x, i32 y) : i32;
fn async Bar() : i32;
// Функция, возвращающая значения типа асинхронной функции, но сама не являющаяся асинхронной.
fn CreateFunc(bool cond) : (async : i32)
{
return select(cond ? Foo( 14, 56 ) : Bar() );
}