我应该 return 调用异步方法的方法中的 ValueTask 或 Task
Should I return a ValueTask or Task in a method which calls an async method
我有一个具有以下签名的方法:
public async Task<Result> CreateAsync(T entity)
{
try
{
await _c.CreateItemAsync(entity);
return Result.Ok();
}
catch (Exception e)
{
return Handle(e); // returns a `Result`
}
}
_c 是 CosmosDB 的 Container
。
现在,我有另一个这样的方法:
public Task<Result> CreateUserAsync(User user)
{
var userEntity = new UserEntity { Id = user.Id, Name = user.Name };
return CreateAsync(userEntity);
}
Result.Ok()
是一个非常简单的自定义静态方法 class Result
:
class Result
{
public static Result Ok() { return new Result(); }.
}
所以,我有两种方法,一种是 Task<Result> CreateUserAsync(User user)
,return 是一个简单的 Task
,无需等待其中的任何内容,但我最后调用的另一个任务return CreateAsync(userEntity);
等待里面的东西。
所以据我了解,CreateAsync()
应该保留为 Task
return 类型,因为它在其中执行异步操作,但我调用它的方法(即CreateUserAsync()
) 也需要保持 Task
,或者可以变成 ValueTask
?
它们在功能上相似,但有一些重要的区别:
- 如果作业立即(同步)完成,则每次都需要分配
Task<T>
(布尔值和小整数周围的一些微不足道的情况除外),其中 ValueTask<T>
可以避免这种情况下的分配
- 在真正异步的情况下,
ValueTask<T>
有潜力 摊销分配,尽管这需要特殊代码(IValueTaskSource<T>
等)
- a
Task<T>
可以等待多次,而 ValueTask<T>
只应等待一次(当多次等待时,行为未定义,作为“2”的副作用"以上)
如果这是一个高吞吐量的代码路径,可能 useful/necessary 考虑机制的分配开销,在这种情况下 ValueTask<T>
开始变得非常诱人 - 但是,如果预先存在的代码可能已经 await
结果不止一次(违反第 3 个要点),这可能会有问题。第一个和第二个要点可能会产生重大影响 如果 异步机制是一个很大的开销(在您的场景中进行测量之后)。
如果这是一个低吞吐量的代码路径,老实说:做你想做的事。 Task<T>
的优点是不需要考虑第三个要点,这很吸引人。
我有一个具有以下签名的方法:
public async Task<Result> CreateAsync(T entity)
{
try
{
await _c.CreateItemAsync(entity);
return Result.Ok();
}
catch (Exception e)
{
return Handle(e); // returns a `Result`
}
}
_c 是 CosmosDB 的 Container
。
现在,我有另一个这样的方法:
public Task<Result> CreateUserAsync(User user)
{
var userEntity = new UserEntity { Id = user.Id, Name = user.Name };
return CreateAsync(userEntity);
}
Result.Ok()
是一个非常简单的自定义静态方法 class Result
:
class Result
{
public static Result Ok() { return new Result(); }.
}
所以,我有两种方法,一种是 Task<Result> CreateUserAsync(User user)
,return 是一个简单的 Task
,无需等待其中的任何内容,但我最后调用的另一个任务return CreateAsync(userEntity);
等待里面的东西。
所以据我了解,CreateAsync()
应该保留为 Task
return 类型,因为它在其中执行异步操作,但我调用它的方法(即CreateUserAsync()
) 也需要保持 Task
,或者可以变成 ValueTask
?
它们在功能上相似,但有一些重要的区别:
- 如果作业立即(同步)完成,则每次都需要分配
Task<T>
(布尔值和小整数周围的一些微不足道的情况除外),其中ValueTask<T>
可以避免这种情况下的分配 - 在真正异步的情况下,
ValueTask<T>
有潜力 摊销分配,尽管这需要特殊代码(IValueTaskSource<T>
等) - a
Task<T>
可以等待多次,而ValueTask<T>
只应等待一次(当多次等待时,行为未定义,作为“2”的副作用"以上)
如果这是一个高吞吐量的代码路径,可能 useful/necessary 考虑机制的分配开销,在这种情况下 ValueTask<T>
开始变得非常诱人 - 但是,如果预先存在的代码可能已经 await
结果不止一次(违反第 3 个要点),这可能会有问题。第一个和第二个要点可能会产生重大影响 如果 异步机制是一个很大的开销(在您的场景中进行测量之后)。
如果这是一个低吞吐量的代码路径,老实说:做你想做的事。 Task<T>
的优点是不需要考虑第三个要点,这很吸引人。