Что бы ни делал GetSomethingAsync()
, это делается вызывающим потоком до тех пор, пока некоторая операция (OP) не может быть завершена сразу (например, io), после чего поток управления передается вызывающей функции, но.Если затем вы получите доступ к свойству Result
возвращенного объекта Task
, поток будет заблокирован.
Это приводит к проблеме, заключающейся в том, что даже после завершения операции поток не узнает об этом, потому что он занят ожиданием завершения Task
Если, однако, вы позволите GetSomethingAsync()
может быть вызван каким-либо потоком пула потоков (что делает Task.Run(...)
) поток пула потоков может завершить OP, и вызывающий поток может быть уведомлен о завершении Task
.
Обновление:
Ваш второй подход не работает, потому что задача все еще была запущена в главном потоке.Если у вас есть этот метод
public static async Task DoStuffAsync()
{
Console.WriteLine($"Doing some stuff1 on thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(50);
Console.WriteLine($"Doing some stuff2 on thread {Thread.CurrentThread.ManagedThreadId}");
}
и вы запустите этот код в приложении с SynchronizationContext
var task = DoStuffAsync();
Console.WriteLine($"Doing main stuff on thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Run(async () => await task);
Он выведет что-то вроде:
Doing some stuff1 on thread 1
Doing main stuff on thread 1
Doing some stuff2 on thread 1
Таким образом, с помощью строки кода Task.Run(async () => await task)
вы добились только того, что поток пула потоков ожидает завершения вашего исходного Task
, но это, в свою очередь, создает новый Task
, который, если его не обработать, ожидая его, вызывает тупик.