【翻译】.NET 5中的性能改进 (19)


在构造之后,应用程序经常访问Uri的各种组件,这一点也得到了改进。特别是,像HttpClient这样的类型通常有一个重复用于发出请求的Uri。HttpClient实现将访问Uri。属性的路径和查询,以发送作为HTTP请求的一部分(例如,GET /dotnet/runtime HTTP/1.1),在过去,这意味着为每个请求重新创建Uri的部分字符串。感谢dotnet/runtime#36460,它现在被缓存(就像IdnHost一样):

private Uri _uri = new Uri("http://github.com/dotnet/runtime"); [Benchmark] public string PathAndQuery() => _uri.PathAndQuery; Method Runtime Mean Ratio Allocated
PathAndQuery   .NET FW 4.8   17.936 ns   1.00   56 B  
PathAndQuery   .NET Core 3.1   30.891 ns   1.72   56 B  
PathAndQuery   .NET 5.0   2.854 ns   0.16    


除此之外,还有许多代码与uri交互的方式,其中许多都得到了改进。例如,dotnet/corefx#41772改进了Uri。EscapeDataString和Uri。EscapeUriString,它根据RFC 3986和RFC 3987对字符串进行转义。这两种方法都依赖于使用不安全代码的共享 helpers,通过char[]来回切换,并且在Unicode处理方面有很多复杂性。这个PR重写了这个 helpers来利用.NET的新特性,比如span和符文,以使escape操作既安全又快速。对于某些输入,增益不大,但是对于涉及Unicode的输入,甚至对于长ASCII输入,增益就很大了。

[Params(false, true)] public bool ASCII { get; set; } [GlobalSetup] public void Setup() { _input = ASCII ? new string('s', 20_000) : string.Concat(Enumerable.Repeat("\xD83D\xDE00", 10_000)); } private string _input; [Benchmark] public string Escape() => Uri.EscapeDataString(_input); Method Runtime ASCII Mean Ratio Allocated
Escape   .NET FW 4.8   False   6,162.59 us   1.00   60616272 B  
Escape   .NET Core 3.1   False   6,483.85 us   1.06   60612025 B  
Escape   .NET 5.0   False   243.09 us   0.04   240045 B  
           
Escape   .NET FW 4.8   True   86.93 us   1.00    
Escape   .NET Core 3.1   True   122.06 us   1.40    
Escape   .NET 5.0   True   14.04 us   0.16    


为Uri.UnescapeDataString提供了相应的改进。这一改变包括使用已经向量化的IndexOf而不是手动的基于指针的循环,以确定需要进行非转义的字符的第一个位置,然后避免一些不必要的代码,并在可行的情况下使用堆栈分配而不是堆分配。虽然使所有操作更快,最大的收益是字符串unescape无关,这意味着EscapeDataString操作没有逃避,只是返回其输入(这种情况也随后帮助进一步dotnet/corefx#41684,使原来的字符串返回时不需要改变):

private string _value = string.Concat(Enumerable.Repeat("abcdefghijklmnopqrstuvwxyz", 20)); [Benchmark] public string Unescape() => Uri.UnescapeDataString(_value); Method Runtime Mean Ratio
Unescape   .NET FW 4.8   847.44 ns   1.00  
Unescape   .NET Core 3.1   846.84 ns   1.00  
Unescape   .NET 5.0   21.84 ns   0.03  


dotnet/runtime#36444和dotnet/runtime#32713使比较uri和执行相关操作(比如将它们放入字典)变得更快,尤其是相对uri。

private Uri[] _uris = Enumerable.Range(0, 1000).Select(i => new Uri($"/some/relative/path?ID={i}", UriKind.Relative)).ToArray(); [Benchmark] public int Sum() { int sum = 0; foreach (Uri uri in _uris) sum += uri.GetHashCode(); return sum; } Method Runtime Mean Ratio
Sum   .NET FW 4.8   330.25 us   1.00  
Sum   .NET Core 3.1   47.64 us   0.14  
Sum   .NET 5.0   18.87 us   0.06  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsssyf.html