Ответ
Нет, не возвращается. Если async-метод завершается синхронно (без реальной асинхронной работы), поток, который его вызвал, блокируется до полного завершения метода, как в обычном синхронном вызове.
Механизм работы:
Ключевое слово async лишь позволяет компилятору переписать метод в состояниевую машину. Если эта машина не встречает незавершённую задачу (await), она выполняется целиком в текущем контексте синхронизации.
Примеры:
// Пример 1: Метод без await.
public async Task<int> CalculateSync()
{
// Вся работа выполняется синхронно. Поток НЕ освобождается.
int result = PerformHeavyComputation(); // Долгий расчёт
return result; // Возвращается уже завершённая задача (Task.FromResult под капотом).
}
// Пример 2: Await на уже завершённой задаче.
public async Task<string> GetCachedValueAsync(string key)
{
if (_cache.TryGetValue(key, out string value))
{
// Task.FromResult создаёт завершённую задачу. Await на ней мгновенен и синхронен.
// Поток НЕ освобождается на время "ожидания".
return value;
}
// Только здесь, при реальном асинхронном вызове, поток может быть освобождён.
return await _database.GetValueAsync(key);
}
Когда поток ВОЗВРАЩАЕТСЯ в пул:
Поток освобождается только в момент, когда await встречает задачу, которая ещё не завершена (например, await httpClient.GetAsync(...), await file.ReadAllTextAsync(...)). В этот момент состояние метода сохраняется, и поток возвращается в пул. Когда асинхронная операция завершится, продолжение метода может быть выполнено на любом свободном потоке из пула (или на исходном, если был контекст синхронизации, как в UI).
Вывод для разработчика: Не стоит помечать метод как async, если в нём нет реальных асинхронных операций. Это создаёт ненужные накладные расходы на создание объекта-машины состояний (AsyncStateMachine). Для простых синхронных методов, возвращающих Task, лучше использовать Task.FromResult.