Ответы:
Лучше всего помечать функцию async void
только в том случае, если это метод fire и Forgot, если вы хотите ждать, вы должны пометить ее как async Task
.
В случае, если вы все еще хотите ждать, оберните его так await Task.Run(() => blah())
await Task.Run(() => An_async_void_method_I_can_not_modify_now())
await Task.Run(() => blah())
вводит в заблуждение. Это не ожидает завершения асинхронной функции blah
, оно просто ожидает (тривиального) создания задачи и продолжается непосредственно перед blah()
ее завершением.
Thread.Sleep
не асинхронно. Этот вопрос о ожидании async void
функции, скажемasync void blah() { Task.Delay(10000); }
Если вы можете изменить сигнатуру своей функции на, async Task
то вы можете использовать код, представленный здесь
Лучшее решение - использовать async Task
. Вам следует избегать async void
по нескольким причинам, одной из которых является составность.
Если метод не может быть выполнен для возврата Task
(например, это обработчик события), то вы можете использовать SemaphoreSlim
для получения сигнала метода, когда он собирается выйти. Подумайте об этом в finally
блоке.
сделать AutoResetEvent, вызвать функцию, затем подождать AutoResetEvent и затем установить его в async void, когда вы знаете, что это сделано.
Вы также можете подождать выполнения задачи, которая возвращается из вашей асинхронной пустоты.
Вам не нужно ничего делать вручную, await
ключевое слово приостанавливает выполнение функции до тех пор, пока не blah()
вернется.
private async void SomeFunction()
{
var x = await LoadBlahBlah(); <- Function is not paused
//rest of the code get's executed even if LoadBlahBlah() is still executing
}
private async Task<T> LoadBlahBlah()
{
await DoStuff(); <- function is paused
await DoMoreStuff();
}
T
тип blah()
возвращаемого объекта
Вы не можете действительно функция так не может бытьawait
void
LoadBlahBlah()
void
LoadBlahBlah()
окончания, а неblah()
Я знаю, что это старый вопрос, но я все еще сталкиваюсь с этой проблемой, и все же нет четкого решения, как правильно сделать это при использовании async / await в методе асинхронной подписи void.
Однако я заметил, что .Wait () работает правильно внутри метода void.
и поскольку async void и void имеют одну и ту же подпись, вам может потребоваться сделать следующее.
void LoadBlahBlah()
{
blah().Wait(); //this blocks
}
Достаточно запутанно async / await не блокирует следующий код.
async void LoadBlahBlah()
{
await blah(); //this does not block
}
Когда вы декомпилируете свой код, я предполагаю, что async void создает внутреннюю задачу (так же, как async Task), но поскольку подпись не поддерживает возврат этой внутренней задачи
это означает, что внутренне асинхронный метод void все еще сможет "ожидать" внутренне асинхронных методов. но внешне не может знать, когда внутренняя задача завершена.
Таким образом, я пришел к выводу, что async void работает как задумано, и если вам нужна обратная связь от внутренней Задачи, вам нужно вместо этого использовать подпись асинхронной Задачи.
надеюсь, моя болтовня имеет смысл для всех, кто также ищет ответы.
Изменить: я сделал пример кода и декомпилировал его, чтобы увидеть, что на самом деле происходит.
static async void Test()
{
await Task.Delay(5000);
}
static async Task TestAsync()
{
await Task.Delay(5000);
}
Превращается в (править: я знаю, что код тела не здесь, а в машинах состояний, но машины состояний были в основном идентичны, поэтому я не стал добавлять их)
private static void Test()
{
<Test>d__1 stateMachine = new <Test>d__1();
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
<TestAsync>d__2 stateMachine = new <TestAsync>d__2();
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
ни AsyncVoidMethodBuilder, ни AsyncTaskMethodBuilder на самом деле не имеют никакого кода в методе Start, который бы намекал на их блокировку, и всегда запускался бы асинхронно после их запуска.
То есть без возврата Задачи не было бы способа проверить, завершена ли она.
как и ожидалось, он только запускает задачу, выполняющую асинхронную работу, а затем продолжает работу в коде. и асинхронная задача, сначала она запускает задачу, а затем возвращает ее.
поэтому я думаю, что мой ответ будет состоять в том, чтобы никогда не использовать async void, если вам нужно знать, когда задача выполнена, для этого и предназначена асинхронная задача.