Асинхронно все вниз?
Попытка понять новый шаблон async/await, у меня есть один вопрос, на который я не могу найти ответ, а именно, если я должен украсить мои методы с помощью async, если я намереваюсь вызывать эти методы из других асинхронных функций или просто верните Task
где это необходимо?
Другими словами, какой из этих классов A, B или C является лучшим и почему?
class A<T>
{
public async Task<T> foo1() //Should be consumed
{
return await foo2();
}
public async Task<T> foo2() //Could be consumed
{
return await foo3();
}
private async Task<T> foo3() //Private
{
return await Task.Run(...);
}
}
class B<T>
{
public async Task<T> foo1() //Should be consumed
{
return await foo2();
}
public async Task<T> foo2() //Could be consumed
{
return await foo3();
}
private Task<T> foo3() //Private
{
return Task.Run(...);
}
}
class C<T>
{
public async Task<T> foo1() //Should be consumed
{
return await foo2();
}
public Task<T> foo2() //Could be consumed
{
return foo3();
}
private Task<T> foo3() //Private
{
return Task.Run(...);
}
}
Кажется излишним переопределять методы, поэтому я, естественно, склоняюсь к C
, но в то же время мне неловко работать с Task<T>
, если вы не используете ключевое слово await
.
Ответы
Ответ 1
Обе версии работают эффективно одинаково, единственное отличие состоит в том, что при использовании await
здесь вы получаете некоторое ограничение производительности (потому что конечный автомат должен быть настроен и, скорее всего, будет использоваться продолжение).
Итак, это сводится к компромиссу: вы хотите, чтобы ваши методы были несколько эффективнее за счет того, чтобы быть менее читабельными? Или вы готовы принести в жертву производительность для удобочитаемости?
Обычно, я бы посоветовал сначала перейти на читаемость и сосредоточиться только на производительности, если профилирование говорит вам об этом. Но в этом случае я думаю, что увеличение удобочитаемости мало, поэтому я бы, вероятно, не использовал await
.
Также обратите внимание, что ваш класс C
все еще не достаточно далеко: foo1()
также не нужен await
.
Ответ 2
async
в сигнатуре есть возможность разрешить компилятору создать перезапись состояния машины содержащегося кода, необходимого для реализации семантики await
в общем случае.
Ваш пример - это особый случай, когда вам не нужна эта переписывание: асинхронная операция - это последнее, что происходит внутри метода. Такой метод уже возможен и действителен в .NET4.0
. Эта совместимость может быть одной из причин избежать async
, когда она вам не нужна.