虽然以下问题通常适用于 C# 中 async/await 的所有用法,但它指的是 Json.NET。JsonConvert.DeserializeObjectAsync()
方法已被开发团队标记为过时,因为它难以维护并且没有多大用处,因为大多数 JSON 文件都很小(请参阅此内容)。
我有一些遵循此结构的代码:
public async Task<CarObj> GetCarAsync()
{
string json = await GetJsonStringFromRestEndpoint();
// At this point, we should already be on a separate thread since we have awaited a long running task.
// 1 - Running this relatively long task on this thread should be fine since we're already on a new thread than the caller.
CarObj obj = JsonConvert.DeserializeObject<CarObj>(json);
// 2 - Would this better for some reason?
CarObj obj2 = await Task.Run(() => JsonConvert.DeserializeObject<CarObj>(json));
}
上面代码中的选项 1 或 2 是更好的解决方案吗?
可以说这主要是基于意见的。但。。。
假设库作者是正确的,您的第一个选择更好。但不是出于你认为的原因。
当await GetJsonStringFromRestEndpoint()
完成时,假设GetCarAsync()
方法是从具有同步上下文的线程调用的,则对DeserializeObject<CarObj>(json);
的调用将在同一线程上进行。
同步调用该方法不是问题的原因不是因为你在不同的线程上(你不是),而是因为正如库作者指出的那样,输入数据不太可能大到存在任何明显的性能问题。与将线程池工作项排队、上下文切换到该线程,然后上下文切换回来所需的时间相比,您可能可以分析整个 JSON 数据并构造CarObj
值。
换句话说,不要使用工作线程来执行计算成本低的工作。
//此时,我们应该已经在一个单独的线程上,因为我们一直在等待一个长时间运行的任务。
否,调用方线程被回调(恢复)。
但是 - 如果这不是您的预期行为 - 我建议添加
.ConfigureAwait(false);
这将节省一些同步工作,之后你会合理地期望处于线程拉线中。