В новой редакции языка появилось новшество ValueTask<T>
.
Правильно ли я понимаю, что его следует использовать в том случае, когда есть вероятность, что задача выполнится быстрее,чем я вызову await
?
Обычный Task умер или все таки в каких-то случаях его нужно использовать?
описание в разделе Generalized async return types
Возврат Task
из асинхронных методов, в некоторых случаях может стать узким местом в производительности. Task
– это ссылочный тип, поэтому при его использовании память под объект будет выделяться в куче. В случаях, когда метод с модификатором async
возвращает кэшированный результат, или выполняется синхронно, дополнительное выделение памяти в куче может занимать значительное время в критических секциях кода. Это может стать очень дорогим, если данные выделения будут происходить в циклах.
новые возможности языка позволяют возвращать из асинхронных методов другие типы, кроме Task
, Task<T>
и void
. Возвращаемый тип по прежнему должен удовлетворять асинхронному шаблону, то есть должен быть доступен метод GetAwaiter
. В качестве конкретного примере в .NET framework был добавлен тип ValueTask
для использования новой возможности:
public async ValueTask<int> Func()
{
await Task.Delay(100);
return 5;
}
Простой оптимизацией может стать использование ValueTask
там, где ранее использовался Task
. Однако, если хочется добавить дополнительную оптимизацию вручную, можно кэшировать результаты асинхронной работы и использовать эти результаты в последующих вызовах. У структуры ValueTask
есть конструктор принимающий Task
в качестве параметра, так что можно создать ValueTask
из возвращаемого значения любого существующего асинхронного метода:
public ValueTask<int> CachedFunc()
{
return (cache) ? new ValueTask<int>(cacheResult) : new ValueTask<int>(LoadCache());
}
private bool cache = false;
private int cacheResult;
private async Task<int> LoadCache()
{
// simulate async work:
await Task.Delay(100);
cacheResult = 100;
cache = true;
return cacheResult;
}
Как и в случаях со всеми рекомендациями по производительности, перед внесением в код масштабных изменений следует сравнить результаты обоих подходов.
Небольшое дополнение к ответу @Grundy и ответ на комментарий @Qutrix:
Для того, чтобы компилятор разрешил использовать ваш собственный Task-подобный тип в качестве возвращаемого значения для асинхронных методов необходимо проделать следующие действия:
Создать этот тип. Он может быть классом или структурой:
public class MyTask { }
[AsyncMethodBuilder(typeof(MyTaskBuilder))]
MyTaskBuilder
. В дальнейшем он будет использоваться компилятором для конструирования вашего Task-подобного типа (минимальный набор методов и свойств указан ниже и в обязательном порядке должен присутствовать в определении MyTaskBuilder
)
public class MyTaskBuilder
{
public static MyTaskBuilder Create() => new MyTaskBuilder();
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { }
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
public void SetResult() { }
public void SetException(Exception exception) { }
public MyTask Task { get; }
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { }
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter,
ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine { }
}
await
так же необходима реализация в классе MyTask
открытого метода GetAwaiter()
, тип возвращаемого значения (MyTaskAwaiter
) которого должен реализовывать интерфейс INotifyCompletion
, иметь открытое свойство IsCompleted
, и конечно же метод GetResult()
(который будет возвращать результат асинхронной операции или же void).[AsyncMethodBuilder(typeof(MyTaskBuilder))]
public class MyTask
{
public static MyTask Run(Action action) { }
public MyTaskAwaiter GetAwaiter() { }
}
public class MyTaskAwaiter : INotifyCompletion
{
public bool IsCompleted { get; }
public void GetResult() { }
public void OnCompleted(Action continuation) { }
}
Таким образом мы получили возможность писать что-то вроде
private async MyTask ExecuteAsync()
{
await MyTask.Run(() => { });
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
Я пытаюсь отобразить элементы из XML в TreeView используя wpf MVVM
Возможно туповатый вопрос но все таки его задам: как можно с генерировать строку чтобы она совпала с той, которую я ввел через ConsoleReadLine(); ? Или...