Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# CancellationToken:为什么不使用AsyncLocal上下文,而不是将参数传递给每个异步方法?_C#_.net_Async Await_Cancellation - Fatal编程技术网

C# CancellationToken:为什么不使用AsyncLocal上下文,而不是将参数传递给每个异步方法?

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的主要原因是速度慢得多。事实上,这是一个字典查找,所以它

我看到microsoft对异步方法强制执行此模式:

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();
        ...
    }

}