【发布时间】:2020-02-26 13:53:05
【问题描述】:
这就是我的意思:
public Task<SomeObject> GetSomeObjectByTokenAsync(int id)
{
string token = repository.GetTokenById(id);
if (string.IsNullOrEmpty(token))
{
return Task.FromResult(new SomeObject()
{
IsAuthorized = false
});
}
else
{
return repository.GetSomeObjectByTokenAsync(token).ContinueWith(t =>
{
t.Result.IsAuthorized = true;
return t.Result;
});
}
}
可以等待上述方法,我认为它与基于 Task 的 A同步 Pattern 建议的操作非常相似? (我知道的其他模式是 APM 和 EAP 模式。)
现在,下面的代码呢:
public async Task<SomeObject> GetSomeObjectByToken(int id)
{
string token = repository.GetTokenById(id);
if (string.IsNullOrEmpty(token))
{
return new SomeObject()
{
IsAuthorized = false
};
}
else
{
SomeObject result = await repository.GetSomeObjectByTokenAsync(token);
result.IsAuthorized = true;
return result;
}
}
这里的主要区别在于该方法是async,并且它使用了await 关键字——那么与之前编写的方法相比,这有什么变化呢?我知道它也可以——等待。任何返回 Task 的方法都可以,除非我弄错了。
每当方法被标记为async 时,我都知道使用这些 switch 语句创建的状态机,并且我知道await 本身不使用线程 - 它根本不会阻塞线程只是去做其他事情,直到它被回调以继续执行上述代码。
但是,当我们使用await 关键字调用它们时,这两种方法之间的根本区别是什么?有什么区别吗?如果有 - 哪个是首选?
编辑:我觉得第一个代码 sn-p 是首选,因为我们有效地 elide async/await 关键字,没有任何影响 - 我们返回一个将继续同步执行的任务,或者热路径上已经完成的任务(可以缓存)。
【问题讨论】:
-
很少,在这种情况下。在您的第一个示例中,
result.IsAuthorized = true将在线程池上运行,而在第二个示例中,它可能在调用GetSomeObjectByToken的同一线程上运行(如果它安装了SynchronizationContext,例如它是UI线程)。GetSomeObjectByTokenAsync抛出异常时的行为也会略有不同。一般来说,await比ContinueWith更受欢迎,因为它几乎总是更具可读性。 -
在this article 中,它被称为“省略”,这似乎是一个很好的词。斯蒂芬绝对了解他的业务。这篇文章的结论本质上是它并不重要,性能方面,但如果你不等待,就会有一些编码陷阱。你的第二个例子是一个更安全的模式。
-
您可能对来自 Microsoft 的 ASP.NET 团队的合作伙伴软件架构师的 Twitter 讨论感兴趣:twitter.com/davidfowl/status/1044847039929028608?lang=en
-
它被称为“状态机”,而不是“虚拟机”。
-
@Enigmativity 谢谢聪明人,我忘记编辑了!
标签: c# multithreading .net-core async-await task-parallel-library