В приведенном ниже коде из-за интерфейса класс LazyBar
должен возвращать задачу из своего метода (и ради аргументов не может быть изменен). Если LazyBar
реализация s необычна в том смысле, что она выполняется быстро и синхронно - каков наилучший способ вернуть задачу No-Operation из метода?
Я пошел с Task.Delay(0)
ниже, однако я хотел бы знать, есть ли у этого какие-либо побочные эффекты производительности, если функция вызывается много (ради аргументов, скажем, сотни раз в секунду):
- Этот синтаксический сахар раскручивается к чему-то большому?
- Это начинает засорять пул потоков моего приложения?
- Достаточно ли ясен компилятор, чтобы иметь дело с
Delay(0)
другими? - Будет
return Task.Run(() => { });
ли по-другому?
Есть ли способ лучше?
using System.Threading.Tasks;
namespace MyAsyncTest
{
internal interface IFooFace
{
Task WillBeLongRunningAsyncInTheMajorityOfImplementations();
}
/// <summary>
/// An implementation, that unlike most cases, will not have a long-running
/// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations'
/// </summary>
internal class LazyBar : IFooFace
{
#region IFooFace Members
public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
{
// First, do something really quick
var x = 1;
// Can't return 'null' here! Does 'Task.Delay(0)' have any performance considerations?
// Is it a real no-op, or if I call this a lot, will it adversely affect the
// underlying thread-pool? Better way?
return Task.Delay(0);
// Any different?
// return Task.Run(() => { });
// If my task returned something, I would do:
// return Task.FromResult<int>(12345);
}
#endregion
}
internal class Program
{
private static void Main(string[] args)
{
Test();
}
private static async void Test()
{
IFooFace foo = FactoryCreate();
await foo.WillBeLongRunningAsyncInTheMajorityOfImplementations();
return;
}
private static IFooFace FactoryCreate()
{
return new LazyBar();
}
}
}
c#
.net
task-parallel-library
async-await
threadpool
Джон Реа
источник
источник
Task.FromResult<object>(null)
.Ответы:
Использование
Task.FromResult(0)
илиTask.FromResult<object>(null)
приведет к меньшим накладным расходам, чем созданиеTask
с выражением no-op. При созданииTask
с заранее определенным результатом не требуются затраты на планирование.Сегодня я бы рекомендовал использовать Task.CompletedTask для достижения этой цели.
источник
return default(YourReturnType);
Task.CompletedTask
мог бы добиться цели! (но требует .net 4.6)Чтобы добавить к ответу Рида Копси об использовании
Task.FromResult
, вы можете еще больше повысить производительность, если кешируете уже выполненную задачу, поскольку все экземпляры выполненных задач одинаковы:С помощью
TaskExtensions.CompletedTask
вы можете использовать один и тот же экземпляр во всем домене приложения.В последней версии .Net Framework (v4.6) добавлено только это со
Task.CompletedTask
статическим свойствомисточник
public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
так же, какpublic async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
. Итак, мы можемreturn CompletedTask;
илиawait CompletedTask;
. Что является более предпочтительным (возможно, более эффективным или более конгруэнтным)?Task.Delay(0)
как в принятом ответе был хороший подход, так как это кэшированная копия готовогоTask
.Начиная с 4.6, теперь
Task.CompletedTask
есть более явное назначение, но оно не толькоTask.Delay(0)
возвращает единственный кэшированный экземпляр, но и тот же единственный кэшированный экземпляр, что иTask.CompletedTask
.Кэшируемая природа ни того, ни другого гарантированно не останется постоянной, но в качестве зависящих от реализации оптимизаций, которые зависят только от реализации в качестве оптимизаций (то есть они все равно будут работать правильно, если реализация изменится на что-то, что все еще остается действительным), использование
Task.Delay(0)
было лучше принятого ответа.источник
Task.CompletedTask
не могу использоваться в проекте PCL, даже если я установил версию .net на 4.6 (профиль 7), только что протестированный в VS2017.Task.CompletedTask => Task.Delay(0);
чтобы поддержать это, поэтому я не не знаю наверняка с макушки головы.Недавно столкнулся с этим и продолжал получать предупреждения / ошибки о недействительности метода.
Мы успокаиваем компилятор, и это проясняет ситуацию:
Это объединяет лучшие из всех советов здесь до сих пор. Оператор return не требуется, если вы на самом деле не делаете что-то в методе.
источник
public Task MyVoidAsyncMethod() {}
полностью такой же, как описанный выше метод. Если есть такой вариант использования, добавьте дополнительный код.источник
Когда вы должны вернуть указанный тип:
источник
Я предпочитаю
Task completedTask = Task.CompletedTask;
решение .Net 4.6, но другой подход - пометить метод async и вернуть void:Вы получите предупреждение (CS1998 - Асинхронная функция без выражения await), но это безопасно игнорировать в этом контексте.
источник
Если вы используете дженерики, все ответы приведут к ошибке компиляции. Вы можете использовать
return default(T);
. Образец ниже, чтобы объяснить дальше.источник
источник