C# CancellationToken:为什么不使用AsyncLocal上下文,而不是将参数传递给每个异步方法?
我看到microsoft对异步方法强制执行此模式:C# CancellationToken:为什么不使用AsyncLocal上下文,而不是将参数传递给每个异步方法?,c#,.net,async-await,cancellation,C#,.net,Async Await,Cancellation,我看到microsoft对异步方法强制执行此模式: async Task<object> DoMyOperationAsync(int par1, string par2,..., CancellationToken token=default(CancellationToken)) { ... CancellationToken.ThrowIfRequested(); ... } 不使用AsyncLocal的主要原因是速度慢得多。事实上,这是一个字典查找,所以它
async Task<object> DoMyOperationAsync(int par1, string par2,..., CancellationToken token=default(CancellationToken))
{
...
CancellationToken.ThrowIfRequested();
...
}
不使用
AsyncLocal
的主要原因是速度慢得多。事实上,这是一个字典查找,所以它应该大约慢20倍(约20ns vs 1ns)
另一个因素是:显性的通常比隐性的好。尽管我同意这是异步实现中非常烦人的一部分。我同意关于静态依赖性的设计/可测试性问题,但字典查找是O(1)+冲突解决方案,以纳秒(因此是20倍)为单位进行比较似乎不太准确,因为它取决于本地环境及其当前条件。同样,通常在O(n)循环中使用令牌,可以在循环开始之前将其分配给本地变量-但大多数情况下,令牌只是通过嵌套的异步调用传递。绝大多数代码实际上无法使用此
CancellationTokenContext
,因为如果您使其跳闸,将无法预测哪些任务会被取消,尤其是,这很容易涉及到之前由完全无关的代码创建的任务。实际上需要取消的可维护代码仍然需要使用其自己的CancellationToken
并一致地传递它,这与此目的背道而驰。如果你有一个代码库,在那里这些东西都无关紧要,你当然可以自由地在你自己的方法中使用这样的模式,但作为一种通用方法,它并不太热。
public class CancellationTokenContext
{
static AsyncLocal<CancellationToken> asyncContext = new AsyncLocal<CancellationToken>();
public static CancellationToken Current {
get {
return asyncContext.Value;
}
set {
asyncContext.Value = value;
}
}
public static void ThrowIfRequested() {
Current.ThrowIfCancellationRequested();
}
}
public class MyClassWithAsyncMethod{
public async Task<object> DoMyOperationAsync(int par1, string par2,...)
{
...
CancellationTokenContext.ThrowIfRequested();
...
}
}