各位老铁们好,相信很多人对影视网站cmp源码分享都不是特别的了解,因此呢,今天就来为大家分享下关于影视网站cmp源码分享以及电影网站源码排名的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!
回复“1”获取开发者路线图
这是
原文|StephenToub
翻译|郑子铭
代码生成(Codegeneration)
.NET7的regex实现有不少于四个引擎:解释器(如果你不明确选择其他引擎,你会得到什么),编译器(你用RegexOptions.Compiled得到什么),非回溯引擎(你用RegexOptions.NonBacktracking得到什么),以及源生成器(你用[GeneratedRegex(..)]得到什么)。解释器和非反向追踪引擎不需要任何类型的代码生成;它们都是基于创建内存中的数据结构,表示如何根据模式匹配输入。不过,其他两个都会生成特定于模式的代码;生成的代码试图模仿你可能写的代码,如果你根本不使用Regex,而是直接写代码来执行类似的匹配。源码生成器吐出的是直接编译到你的汇编中的C59186提供了源代码生成器的初始实现。这是编译器的直接移植,有效地将IL逐行翻译成C,类似于你通过ILSpy等反编译器运行生成的IL。一系列的PR接着对源码生成器进行了迭代和调整,但最大的改进来自于对编译器和源码生成器的共同改变。在.NET5之前,编译器吐出的IL与解释器的工作非常相似。解释器收到了一系列指令,它逐一进行解释,而编译器收到了同样的一系列指令,只是发出了处理每个指令的IL。它有一些提高效率的机会,如循环解卷,但很多价值被留在了桌子上。在.NET5中,为了支持没有回溯的模式,增加了另一种路径;这种代码路径是基于被解析的节点树,而不是基于一系列的指令,这种更高层次的形式使编译器能够获得更多关于模式的见解,然后可以用来生成更有效的代码。在.NET7中,对所有regex特性的支持都是在多个PR的过程中逐步加入的,特别是dotnet/runtime61698用于回溯单字符懒惰循环,dotnet/runtime61906用于其他回溯循环以及回引和条件。在这一点上,唯一缺少的功能是对RegexOptions.RightToLeft和lookbehinds的支持(这是以从右到左的方式实现的),而且我们根据这些功能相对较少的使用情况决定,我们没有必要为了启用它们而保留旧的编译器代码。所以,dotnet/runtime66127和dotnet/runtime的好处之一是它使迭代变得容易。每次你输入一个模式并看到生成器发出的东西,就像被要求对别人的代码进行审查一样,你经常看到一些值得评论的”新”东西,或者在这种情况下,改进生成器以解决这个问题。因此,一堆PR的起源是基于审查生成器发出的东西,然后调整生成器以做得更好(由于编译器实际上是和源生成器一起完全重写的,它们保持相同的结构,很容易从一个移植到另一个的改进)。例如,dotnet/runtime69198调整了一些比较的执行方式,以便向JIT传达足够的信息,从而消除一些后续的边界检查,dotnet/runtime68560做到了这一点,例如,像hello这样的简单模式根本不会发出一个循环,而会有一个更简单的扫描实现,比如。
protectedoverridevoidScan(ReadOnlySpan<char>inputSpan){if(TryFindNextPossibleStartingPosition(inputSpan)){//ThesearchinTryFindNextPossibleStartingPositionperformedtheentirematch.intstart=base.runtextpos;intend=base.runtextpos=start+5;base.Capture(0,start,end);}}
例如,dotnet/runtime62620中介绍的IsWordChar辅助函数)可以在多个生成的regex中共享,如果相同的模式/选项/超时组合在同一个程序集的多个地方使用,我们希望能够共享完全相同的regex实现(dotnet/runtime66432,然后dotnet/runtime11中新的文件本地类型特性(dotnet/roslyn67365改进了一些在现实世界中常见的情况,比如特别识别[\\d\\D]、[\\s\\S]和[\\w\\W]这样的集合意味着”匹配任何东西”(就像RegexOptions.Singleline模式中的.一样),在这种情况下,围绕处理”匹配任何东西”的现有优化可以启动。
privatestaticreadonlystrings_haystack=newstring(‘a’,1_000_000);privateRegex_regex=newRegex(@”([\\s\\S]*)”,RegexOptions.Compiled);[Benchmark]publicMatchMatch()=>_regex.Match(s_haystack);
方法运行时平均值比率Match.NET6.01,934,393.69ns1.000Match.NET7.091.80ns0.000
或者dotnet/runtime72328,它改进了对涉及字符类减法的字符类的处理;来自@teo-tsirpanis的dotnet/runtime67133,它增加了一个更严格的边界检查,当它确实发出这样一个查找表时;以及dotnet/runtime66142,来自@Clockwork-Muse的dotnet/runtime62325都将Regex的使用转为使用[GeneratedRegex(..)]。dotnet/runtime68766还删除了RegexOptions.CultureInvariant的用法。指定CultureInvariant会改变IgnoreCase的行为,即交替使用大小写表;如果没有指定IgnoreCase,也没有内联的大小写敏感选项((?i)),那么指定CultureInvariant就是一个nop。但这有可能是一个昂贵的选择。对于任何注重规模的代码来说,Regex实现的结构方式是尽量使其对小规模用户友好。如果你只做newRegex(pattern),我们真的希望能够静态地确定编译器和非反向追踪的实现是不需要的,这样修剪者就可以删除它而不产生可见的和有意义的负面影响。然而,修剪器的分析还没有复杂到可以准确地看到哪些选项被使用,并且只在使用RegexOptions.Compiled或RegexOptions.NonBacktracking时保留额外的引擎链接;相反,任何使用需要RegexOptions的重载都会导致该代码继续被引用。通过摆脱这些选项,我们增加了应用程序中没有代码使用这个构造函数的机会,这反过来会使这个构造函数、编译器和非回溯实现被裁剪掉。
集合(Collections)
System.Collections在.NET7中的投资并没有像以前的版本那样多,尽管许多低级别的改进也对集合产生了涓滴效应。例如,Dictionary<,>的代码在.NET6和.NET7之间没有变化,但即便如此,这个基准还是集中在字典的查找上。
privateDictionary<int,int>_dictionary=Enumerable.Range(0,10_000).ToDictionary(i=>i);[Benchmark]publicintSum(){Dictionary<int,int>dictionary=_dictionary;intsum=0;for(inti=0;i<10_000;i++){if(dictionary.TryGetValue(i,outintvalue)){sum+=value;}}returnsum;}
显示出.NET6和.NET7之间的吞吐量有可观的改善。
方法运行时平均值比率代码大小Sum.NET6.051.18us1.00431BSum.NET7.043.44us0.85413B
除此之外,在集合的其他地方也有明确的改进。例如,ImmutableArray。作为提醒,ImmutableArray是一个非常薄的基于结构的包装,围绕着T[],隐藏了T[]的可变性;除非你使用不安全的代码,否则ImmutableArray的长度和浅层内容都不会改变(我说的浅层是指直接存储在该数组中的数据不能被改变,但如果数组中存储有可变参考类型,这些实例本身仍然可能有其数据被改变)。因此,ImmutableArray也有一个相关的”builder”类型,它确实支持突变:你创建builder,填充它,然后将内容转移到ImmutableArray中,它就永远冻结了。在来自@grbell-ms的dotnet/runtime61196来自@lateapexearlyspeed,它将ImmutableArray带入了基于span的时代,为ImmutableArray添加了大约10个新方法,这些方法与span和ReadOnlySpan互操作。从性能的角度来看,这些方法很有价值,因为它意味着如果你在span中拥有你的数据,你可以将其放入ImmutableArray中,而不会产生除ImmutableArray本身将创建的分配之外的额外分配。来自@RaymondHuy的dotnet/runtime58793,该操作现在只需调用BitOperations.Log2,如果支持多个硬件本征(例如Lzcnt.LeadingZeroCount、ArmBase.LeadingZeroCount、X86Base.BitScanReverse),则可通过这些本征实现。来自@johnthcall的dotnet/runtime67923。ConditionalWeakTable<TKey,TValue>是一个大多数开发者没有使用过的集合,但是当你需要它时,你就需要它。它主要用于两个目的:将额外的状态与一些对象相关联,以及维护对象的弱集合。从本质上讲,它是一个线程安全的字典,不维护它所存储的任何东西的强引用,但确保与一个键相关的值将保持根基,只要相关的键是根基的。它暴露了许多与ConcurrentDictionary<,>相同的API,但是对于向集合中添加项目,它历来只有一个Add方法。这意味着如果消费代码的设计需要尝试将集合作为一个集合,其中重复是很常见的,当尝试添加一个已经存在于集合中的项目时,也会经常遇到异常。现在,在.NET7中,它有一个TryAdd方法,可以实现这样的使用,而不可能产生这种异常的代价(也不需要添加try/catch块来抵御这些异常)。
语言集成查询(LINQ)
让我们继续讨论语言集成查询(Language-IntegratedQuery)(LINQ)。LINQ是一个几乎每个.NET开发者都会使用的生产力特性。它使复杂的操作能够被简单地表达出来,无论是通过语言集成查询语法还是通过直接使用System.Linq.Enumerable上的方法。然而,这种生产力和表现力是以一定的开销为代价的。在绝大多数情况下,这些成本(如委托和闭包分配、委托调用、在任意枚举对象上使用接口方法与直接访问索引器和长度/计数属性等)不会产生重大影响,但对于真正的热点路径,它们可以而且确实以一种有意义的方式出现。这导致一些人宣布LINQ在他们的代码库中是被广泛禁止的。在我看来,这是一种误导;LINQ是非常有用的,有它的位置。在.NET中,我们使用了LINQ,只是在使用的地方上比较实际和周到,避免在我们已经优化为轻量级和快速的代码路径中使用它,因为预期这些代码路径可能对消费者很重要。因此,虽然LINQ本身的性能可能不如手工滚动的解决方案那么快,但我们仍然非常关心LINQ的实现性能,以便它能在越来越多的地方被使用,并且在使用它的地方尽可能地减少开销。在LINQ的操作之间也有差异;有200多个提供各种功能的重载,其中一些重载根据其预期用途,比其他重载受益于更多的性能调整。
dotnet/runtime语言在类型系统方面存在分歧的罕见情况。如果你把Console.WriteLine((object)newuint[42]isint[]);改为Console.WriteLine(newuint[42]isint[]);,也就是去掉(object)的转换,你会发现它开始打印出False而不是True。这是因为C64624中得到了进一步的发展,它扩大了支持的输入类型和利用的操作。首先,它引入了一个私有助手,用于从某些类型的IEnumerable输入中提取ReadOnlySpan,即今天那些实际上是T[]或List的输入;与之前的PR一样,它使用GetType()==typeof(T[])形式,以避免对其他输入的显著惩罚。这两种类型都能为实际的存储提取ReadOnlySpan,在T[]的情况下是通过转换,在List的情况下是通过.NET5中引入的CollectionsMarshal.AsSpan方法。一旦我们有了这个跨度,我们就可以做一些有趣的事情。这个PR。
扩展了之前的Min
(IEnumerable)和Max(IEnumerable)优化,不仅适用于int[]和long[],也适用于List和List。
为Average
(IEnumerable)和Sum(IEnumerable)使用直接跨距访问,适用于int、long、float、double或decimal,所有数组和列表。
类似地,对Min
(IEnumerable)和Max(IEnumerable)使用直接的跨度访问,适用于T是浮点数、双数和小数。
对数组和列表的Average
(IEnumerable)进行矢量化。
这方面的影响在微观基准中是很明显的,比如说
privatestaticfloat[]CreateRandom(){varr=newRandom(42);varresults=newfloat[10_000];for(inti=0;i<results.Length;i++){results[i]=(float)r.NextDouble();}returnresults;}privateIEnumerable<float>_floats=CreateRandom();[Benchmark]publicfloatSum()=>_floats.Sum();[Benchmark]publicfloatAverage()=>_floats.Average();[Benchmark]publicfloatMin()=>_floats.Min();[Benchmark]publicfloatMax()=>_floats.Max();
方法运行时平均值比率已分配分配比率Sum.NET6.039.067us1.0032B1.00Sum.NET7.014.349us0.37–0.00Average.NET6.041.232us1.0032B1.00Average.NET7.014.378us0.35–0.00Min.NET6.045.522us1.0032B1.00Min.NET7.09.668us0.21–0.00Max.NET6.041.178us1.0032B1.00Max.NET7.09.210us0.22–0.00
之前的LINQPR是来自于使现有操作更快的例子。但有时性能的提高来自于新的API,这些API在某些情况下可以用来代替以前的API,以进一步提高性能。一个这样的例子来自于@deeprobin在dotnet/runtime71564中得到了改进。LINQ中最流行的方法之一是Enumerable.OrderBy(及其逆序OrderByDescending),它可以创建一个输入枚举的排序副本。为此,调用者向OrderBy传递一个Func<TSource,TKey>谓词,OrderBy用它来提取每个项目的比较键。然而,想要以自己为键对项目进行排序是比较常见的;这毕竟是Array.Sort等方法的默认值,在这种情况下,OrderBy的调用者最终会传入一个身份函数,例如OrderBy(x=>x)。为了消除这个障碍,.NET7引入了新的Order和OrderDescending方法,根据Distinct和DistinctBy等对的精神,执行同样的排序操作,只是隐含了一个代表调用者的x=>x。但除了性能之外,这样做的一个好处是,实现者知道键将与输入相同,它不再需要为每个项目调用回调以检索其键,也不需要分配一个新的数组来存储这些键。因此,如果你发现自己在使用LINQ,并达到OrderBy(x=>x),考虑使用Order(),并获得(主要是分配)的好处。
[Params(1024)]publicintLength{get;set;}privateint[]_arr;[GlobalSetup]publicvoidSetup()=>_arr=Enumerable.Range(1,Length).Reverse().ToArray();[Benchmark(Baseline=true)]publicvoidOrderBy(){foreach(int_in_arr.OrderBy(x=>x)){}}[Benchmark]publicvoidOrder(){foreach(int_in_arr.Order()){}}
方法长度平均值比率已分配分配比率OrderBy102468.74us1.0012.3KB1.00Order102466.24us0.968.28KB0.67
文件输入输出(FileI/O)
.NET6有一些巨大的文件I/O改进,特别是对FileStream进行了完全重写。虽然.NET7没有任何单一的变化,但它确实有大量的改进,可衡量的”移动针”,而且是以不同的方式。
性能改进的一种形式也被伪装成可靠性改进,就是提高对取消请求的响应速度。取消的速度越快,系统就能越快地归还正在使用的宝贵资源,等待该操作完成的事情也就能越快地被解禁。在.NET7中已经有了一些类似的改进。
在某些情况下,它来自于添加了可取消的重载,而这些东西以前根本就不是可取消的。来自@bgrainger的dotnet/runtime64301又在TextReader返回的StreamReader类型上重载了这些方法(以及其他缺少重载)。和StreamReader.(有趣的是,这些被定义为两种不同的类型,这是不必要的,所以这个PR也统一了让两者都使用StreamReader的变体,因为它满足了两者所需的类型)。你可以在dotnet/runtime72503(以及随后在dotnet/runtime#72612中的调整),我们已经使其余的操作在Windows上也可以完全取消。目前,Windows不支持匿名管道的重叠I/O,所以对于匿名管道和为同步I/O打开的命名管道,Windows的实现将只是委托给基本的Stream实现,它将向ThreadPool排队一个工作项,以调用同步对应项,只是在另一个线程。取而代之的是,现在的实现会排队等待工作项,但不是仅仅调用同步方法,而是做一些注册取消的前后工作,传入即将执行I/O的线程的ID。如果请求取消,实现就会使用CancelSynchronousIo来中断它。这里有一个竞赛条件,即当线程注册取消时,可以请求取消,这样CancelSynchronousIo就会在操作实际开始前被调用。因此,有一个小的自旋循环,如果在注册发生的时间和实际执行同步I/O的时间之间有取消请求,取消线程将自旋,直到I/O被启动,但这种情况预计会非常罕见。另一边还有一个竞赛条件,即CancelSynchronousIo在I/O已经完成后被请求;为了解决这个竞赛,该实现依赖于CancellationTokenRegistration.Dispose的保证,它承诺相关的回调将永远不会被调用或在Dispose返回时已经完全执行完毕。这个实现不仅完成了拼图,使Windows和Unix的匿名和命名管道上的所有异步读/写操作都可以取消,而且实际上还提高了正常的吞吐量。
privateStream_server;privateStream_client;privatebyte[]_buffer=newbyte[1];privateCancellationTokenSource_cts=newCancellationTokenSource();[Params(false,true)]publicboolCancelable{get;set;}[Params(false,true)]publicboolNamed{get;set;}[GlobalSetup]publicvoidSetup(){if(Named){stringname=Guid.NewGuid().ToString(“N”);varserver=newNamedPipeServerStream(name,PipeDirection.Out);varclient=newNamedPipeClientStream(“.”,name,PipeDirection.In);Task.WaitAll(server.WaitForConnectionAsync(),client.ConnectAsync());_server=server;_client=client;}else{varserver=newAnonymousPipeServerStream(PipeDirection.Out);varclient=newAnonymousPipeClientStream(PipeDirection.In,server.ClientSafePipeHandle);_server=server;_client=client;}}[GlobalCleanup]publicvoidCleanup(){_server.Dispose();_client.Dispose();}[Benchmark(OperationsPerInvoke=1000)]publicasyncTaskReadWriteAsync(){CancellationTokenct=Cancelable?_cts.Token:default;for(inti=0;i<1000;i++){ValueTask<int>read=_client.ReadAsync(_buffer,ct);await_server.WriteAsync(_buffer,ct);awaitread;}}
原文链接
PerformanceImprovementsin.NET7
请在公众号后台
好了,关于影视网站cmp源码分享和电影网站源码排名的问题到这里结束啦,希望可以解决您的问题哈!
