为什么String.IsNullOrEmpty比string.length减得快? [英] Why is String.IsNullOrEmpty faster than String.Length?
问题描述
ILSpy显示, String.IsNullOrEmpty
在 string.length减
方面实现。不过,为什么是 String.IsNullOrEmpty(S)
快于 s.Length == 0
?
例如,它的5%,在此测试中领先优势:
VAR秒表= Enumerable.Range(0,4)。选择(_ =>新建秒表())。的ToArray();
VAR字符串=A,B ,, C,DE,女,, G,H ,,,, I,J ,, K,L,MN,OP,Q,R,STU,V,W,X,Y, Z,斯普利特('')。
VAR测试人员=新的函数功能:其中,字符串,布尔> [] {S =>小号==的String.Empty,S => s.Length == 0,S => String.IsNullOrEmpty(S)中,s =>小号==};
诠释计数= 0;
的for(int i = 0; I< 10000; ++ I){
秒表[I%4]。开始();
对于(INT J = 0; J< 1000; ++ j)条
数+ = strings.Count(测试[I%4]);
秒表[I%4] .Stop();
}
(其它基准测试显示了相似的结果。这其中最小克鲁夫特我的计算机上运行的影响。另外,顺便说一句,比较空字符串测试师出同在比 13%左右速度较慢IsNullOrEmpty
)
此外,为什么 IsNullOrEmpty
只有更快的x86,而在x64 string.length减
约9%的速度?
更新:测试设置详细信息:.NET 4.0的64位运行的是Windows 7,英特尔酷睿i5处理器,编译控制台项目优化code已启用。然而,在模块加载燮preSS JIT优化也被启用(见接受的答案和注释)。
通过优化完全启用,长度
比 IsNullOrEmpty
更快的委托和删除其他开销约14%,如在此测试
VAR字符串=A,B ,, C,DE,女,, G,H ,,,, I,J ,, K,L,MN,OP,Q, R 1,STU,V ,,W¯¯...,X ,,, YC,Z,斯普利特('')。
诠释计数= 0;
对于(UINT I = 0; I<亿; ++ I)
数+ =字符串[我%32] .Length == 0? 1:0; //更换String.IsNullOrEmpty长度测试
这是因为你从Visual Studio其中prevents JIT编译器优化code之内跑了基准测试。如果没有优化,这code制造的的 String.IsNullOrEmpty 的
00000000推送EBP
00000001 MOV EBP,ESP
00000003分ESP,8
00000006 MOV DWORD PTR [EBP-8],ECX
00000009 CMP DWORD PTR DS:[00153144h] 0
00000010 00000017济
00000012电话64D85BDF
00000017 MOV ECX,DWORD PTR [EBP-8]
0000001a电话63EF7C0C
0000001f MOV DWORD PTR [EBP-4],EAX
00000022 MOVZX EAX,字节PTR [EBP-4]
00000026 MOV ESP,EBP
00000028弹出EBP
00000029 RET
和现在比较,产生的code的长度== 0 的
00000000推送EBP
00000001 MOV EBP,ESP
00000003分ESP,8
00000006 MOV DWORD PTR [EBP-8],ECX
00000009 CMP DWORD PTR DS:[001E3144h] 0
00000010 00000017济
00000012电话64C95BDF
00000017 MOV ECX,DWORD PTR [EBP-8]
0000001a CMP DWORD PTR [ECX],ECX
0000001c电话64EAA65B
00000021 MOV DWORD PTR [EBP-4],EAX
00000024 CMP DWORD PTR [EBP-4],0
00000028 SETE人
0000002b MOVZX EAX,人
0000002e MOV ESP,EBP
00000030弹出EBP
00000031 RET
您可以看到,$ C $下的长度== 0 的做的一切,做$ C $下的 String.IsNullOrEmpty 的,但另外它试图像傻傻的再次转换布尔值(长度比较返回),以布尔,这使得它比的 String.IsNullOrEmpty 的慢。
如果您编译程序启用优化(释放模式),并直接从Windows中运行.exe文件,由JIT编译器生成code好得多。对于 String.IsNullOrEmpty 的是:
001f0650推EBP
001f0651 MOV EBP,ESP
001f0653测试ECX,ECX
001f0655济001f0663
001f0657 CMP DWORD PTR [ECX + 4],0
001f065b SETE人
001f065e MOVZX EAX,人
001f0661 JMP 001f0668
001f0663 MOV EAX,1
001f0668和EAX,0FFh的
001f066d弹出EBP
001f066e RET
和长度== 0 的:
001406f0 CMP DWORD PTR [ECX + 4],0
001406f4 SETE人
001406f7 MOVZX EAX,人
001406fa RET
通过这个code,结果与预期一致,即长度== 0 的稍快于 String.IsNullOrEmpty 的。
另外值得一提的,是使用LINQ,拉姆达EX pressions并在基准计算模是不是一个好主意,因为这些操作慢(相对于字符串比较),使基准不准确的结果。
ILSpy shows that String.IsNullOrEmpty
is implemented in terms of String.Length
. But then why is String.IsNullOrEmpty(s)
faster than s.Length == 0
?
For example, it's 5% faster in this benchmark:
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();
}
(Other benchmarks show similar results. This one minimized the effect of cruft running on my computer. Also, as an aside, the tests comparing to empty strings came out the same at about 13% slower than IsNullOrEmpty
.)
Additionally, why is IsNullOrEmpty
only faster on x86, whereas on x64 String.Length
is about 9% faster?
Update: Test setup details: .NET 4.0 running on 64-bit Windows 7, Intel Core i5 processor, console project compiled with "Optimize code" enabled. However, "Suppress JIT optimization on module load" was also enabled (see accepted answer and comments).
With optimization fully enabled, Length
is about 14% faster than IsNullOrEmpty
with the delegate and other overhead removed, as in this test:
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
It's because you ran your benchmark from within Visual Studio which prevents JIT compiler from optimizing code. Without optimizations, this code is produced for 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
and now compare it to code produced for 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
You can see, that code for Length == 0 does everything that does code for String.IsNullOrEmpty, but additionally it tries something like foolishly convert boolean value (returned from length comparison) again to boolean and this makes it slower than String.IsNullOrEmpty.
If you compile program with optimizations enabled (Release mode) and run .exe file directly from Windows, code generated by JIT compiler is much better. For String.IsNullOrEmpty it is:
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
and for Length == 0:
001406f0 cmp dword ptr [ecx+4],0
001406f4 sete al
001406f7 movzx eax,al
001406fa ret
With this code, result are as expected, i.e. Length == 0 is slightly faster than String.IsNullOrEmpty.
It's also worth mentioning, that using Linq, lambda expressions and computing modulo in your benchmark is not such a good idea, because these operations are slow (relatively to string comparison) and make result of benchmark inaccurate.
这篇关于为什么String.IsNullOrEmpty比string.length减得快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!