Edw*_*rey 19 .net c# string performance is-empty
ILSpy表明它String.IsNullOrEmpty是以实现的方式实现的String.Length.但那么为什么String.IsNullOrEmpty(s)速度比s.Length == 0?
例如,它在此基准测试中的速度提高了5%:
var stopwatches = Enumerable.Range(0, 4).Select(_ => new Stopwatch()).ToArray();
var strings = "A,B,,C,DE,F,,G,H,,,,I,J,,K,L,MN,OP,Q,R,STU,V,W,X,Y,Z,".Split(',');
var testers = new Func<string, bool>[] { s => s == String.Empty, s => s.Length == 0, s => String.IsNullOrEmpty(s), s => s == "" };
int count = 0;
for (int i = 0; i < 10000; ++i) {
stopwatches[i % 4].Start();
for (int j = 0; j < 1000; ++j)
count += strings.Count(testers[i % 4]);
stopwatches[i % 4].Stop();
}
Run Code Online (Sandbox Code Playgroud)
(其他基准测试显示出类似的结果.这个基准测试最大限度地减少了在我的计算机上运行的影响.另外,与空字符串相比,测试结果与空字符串相比大约低了13%IsNullOrEmpty.)
另外,为什么IsNullOrEmptyx86上的速度更快,而x64的String.Length速度提高约9%呢?
更新:测试设置详细信息:在64位Windows 7,Intel Core i5处理器上运行的.NET 4.0,启用了"优化代码"编译的控制台项目.但是,还启用了"抑制模块加载时的JIT优化"(请参阅接受的答案和注释).
完全启用优化后,与委托Length相比IsNullOrEmpty,移除速度快14%,并且删除了其他开销,如此测试:
var strings = "A,B,,C,DE,F,,G,H,,,,I,J,,K,L,MN,OP,Q,R,,STU,V,,W,,X,,,Y,,Z,".Split(',');
int count = 0;
for (uint i = 0; i < 100000000; ++i)
count += strings[i % 32].Length == 0 ? 1 : 0; // Replace Length test with String.IsNullOrEmpty
Run Code Online (Sandbox Code Playgroud)
Ňuf*_*Ňuf 22
这是因为您从Visual Studio中运行了基准测试,这阻止了JIT编译器优化代码.如果没有优化,则会为String.IsNullOrEmpty生成此代码
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 mov dword ptr [ebp-8],ecx
00000009 cmp dword ptr ds:[00153144h],0
00000010 je 00000017
00000012 call 64D85BDF
00000017 mov ecx,dword ptr [ebp-8]
0000001a call 63EF7C0C
0000001f mov dword ptr [ebp-4],eax
00000022 movzx eax,byte ptr [ebp-4]
00000026 mov esp,ebp
00000028 pop ebp
00000029 ret
Run Code Online (Sandbox Code Playgroud)
现在将它与为Length == 0生成的代码进行比较
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,8
00000006 mov dword ptr [ebp-8],ecx
00000009 cmp dword ptr ds:[001E3144h],0
00000010 je 00000017
00000012 call 64C95BDF
00000017 mov ecx,dword ptr [ebp-8]
0000001a cmp dword ptr [ecx],ecx
0000001c call 64EAA65B
00000021 mov dword ptr [ebp-4],eax
00000024 cmp dword ptr [ebp-4],0
00000028 sete al
0000002b movzx eax,al
0000002e mov esp,ebp
00000030 pop ebp
00000031 ret
Run Code Online (Sandbox Code Playgroud)
你可以看到,Length == 0的代码完成了为String.IsNullOrEmpty编写代码的所有代码,但是它还尝试将笨拙地将布尔值(从长度比较返回)再次转换为布尔值,这使得它比String.IsNullOrEmpty慢.
如果编译启用了优化的程序(发布模式)并直接从Windows运行.exe文件,则JIT编译器生成的代码要好得多.对于String.IsNullOrEmpty,它是:
001f0650 push ebp
001f0651 mov ebp,esp
001f0653 test ecx,ecx
001f0655 je 001f0663
001f0657 cmp dword ptr [ecx+4],0
001f065b sete al
001f065e movzx eax,al
001f0661 jmp 001f0668
001f0663 mov eax,1
001f0668 and eax,0FFh
001f066d pop ebp
001f066e ret
Run Code Online (Sandbox Code Playgroud)
并且对于长度== 0:
001406f0 cmp dword ptr [ecx+4],0
001406f4 sete al
001406f7 movzx eax,al
001406fa ret
Run Code Online (Sandbox Code Playgroud)
使用此代码,结果如预期,即Length == 0略快于String.IsNullOrEmpty.
值得一提的是,在你的基准测试中使用Linq,lambda表达式和计算模数并不是一个好主意,因为这些操作很慢(相对于字符串比较)并且使得基准测试的结果不准确.