Ответ 1
Позволяет изолировать каждую часть кода:
public static void ThreadDoWork()
{
using (var dispose = new ThreadDispose())
{
dispose.RunAsync();
}
}
public void RunAsync()
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.Sleep(3000);
});
}
Что вы делаете в этом первом фрагменте кода, это работа в очереди на поток threadpool. Поскольку вы выполняете этот код внутри области using
и запускаете асинхронно в другом потоке, он предоставляет немедленно. Вот почему вы видите сообщение dispose внутри вашего текстового файла.
public static async void TaskDoWork()
{
using (var dispose = new TaskDispose())
{
await dispose.RunAsync();
}
}
public class TaskDispose : IDisposable
{
public async Task RunAsync()
{
await Task.Delay(3000);
}
}
Когда вы await
внутри вашего метода, то, что вы на самом деле говорите, есть нечто вроде следующих: "Выполните этот код. Поскольку он асинхронен по своей природе, я верну управление обратно вызывающему методу, пожалуйста, позвоните мне, как только вы завершить асинхронную операцию".
Ваш код попадает в ключе await
и возвращает управление вашему методу Main
. Внутри Main
ваш метод async - это последний фрагмент кода для выполнения, поэтому заканчивается ваше приложение и не дает возможности для выполнения вашего метода Dispose
.
Если вы хотите его утилизировать, вам придется изменить тип возврата с void
на Task
и явно Wait
:
public static async Task TaskDoWork()
{
using (var dispose = new TaskDispose())
{
await dispose.RunAsync();
}
}
И теперь:
static void Main(string[] args)
{
ThreadDoWork();
TaskDoWork().Wait();
}
Боковое примечание:
Существует несколько рекомендаций, которые следует соблюдать:
-
async void
предназначен для совместимости с обработчиками событий, редко бывает за пределами этой области, где он должен использоваться. Вместо этого используйтеasync Task
. -
Методы, выполняющие асинхронную работу с использованием TAP (Task Asynchronous Pattern), должны заканчиваться postfix
Async
.TaskDoWork
должен бытьTaskDoWorkAsync
-
Использование
Wait
вTask
может вызвать взаимоблокировки. В этом конкретном случае это происходит не потому, что консольное приложение не имеетSynchronizationContext
и использует потоковые пулы. Рекомендованный подход заключается в том, чтобы "асинхронно полностью" и использоватьawait
В aync-wait tag wiki есть замечательные материалы для чтения. Обязательно проверьте его.