我应该等待ValueTask<T>吗?

12
请问哪种是有效的 ValueTask 实现方式? 缓存服务从缓存或数据库返回数据。
public async ValueTask<IList<HrEmploymentDataCustom>> GetEmployeesFacts()
{
    try
    {
        var facts = (List<HrEmploymentDataCustom>) _memoryCache.Get("facts");
        return facts ?? await _accountService.GetEmploymentFacts(DetailsRequestType.All, null);
    }
    catch (Exception e)
    {
        var tc = new TelemetryClient();
        tc.TrackException(e);
        return null;
    }
}

这是:var employeesFacts = await _cacheService.GetEmployeesFacts();
还是:var employeesFacts = _cacheService.GetEmployeesFacts().Result;
有点困惑。

9
如果可以的话,总是使用 await 等待一个任务。使用 .Result 阻塞线程在最好情况下是低效的,在最坏情况下会导致死锁。 - Crowcoder
我更喜欢使用await,这样你可以获得更好的异常处理(如果出现问题)... .Result会将所有错误都包装在AggregateException中。 - Ferryzijl
是的,但如果返回值呢?这个方法是否足够智能,不会异步执行(从性能角度考虑)? - sziszu
@Oram 不,ValueTask类似于Task,但并不相同。 - Camilo Terevinto
显示剩余3条评论
1个回答

40

这会是什么意思:

var employeesFacts = await _cacheService.GetEmployeesFacts();
通常是的。

或者

var employeesFacts = _cacheService.GetEmployeesFacts().Result;

有点困惑。

绝对不能使用 ValueTask,除非你知道它与普通 Task 的不同之处,并且有理由这样做,因为实证性的性能研究表明常规任务是集合压力的主要贡献者。几乎所有的情况下都应该使用普通任务。

无论值类型还是引用类型,你都不会更改任务的使用方式。你需要使用 await 来等待任务完成。

无论是值类型还是引用类型,你永远不会使用 .Result 来获取任务结果。为什么呢?因为假设任务尚未完成:那么 .Result 将会同步等待任务完成。假设工作流程的最后一步当前在队列中等待调度。你让那个线程进入睡眠状态!现在线程正在睡觉,等待它自己唤醒它,所以它将永远睡觉。几乎总是不要使用 .Result


这是我的想法,那么在上述情况下使用ValueTask而不是Task是否值得呢? - sziszu
12
请进行一项实证性能研究,以确定任务是否是产生不必要的收集压力的主要因素。如果是,再次进行同样的研究,使用价值任务并查看结果是否有所改变。通过科学实验回答你的问题,而非向陌生人询问他们未编写过也从未运行过的程序的性能特征。您编写了程序,请对其进行测试! - Eric Lippert
4
如果你知道自己在做什么(例如正在使用任务和IAsyncEnumerables的工作线程),则可以使用“.Result”或“.Wait()”(在任务上),以使其更易于理解。但是,我会说:除非必须这样做并且您绝对知道自己在做什么,否则永远不要使用它。 - Felix K.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接