for-loop(downto,Reversed) vs for-loop(increase mode) vs while-loop in Delphi
for-loop(downto,Reversed) vs for-loop(increase mode) vs while-loop in Delphi
我有一个微优化问题。我有 3 种处理 typed-Pointer(array) 的方法。哪个更好?
1
for I:=0 to ArrCount-1 do
begin // I:Var is unused in below-block
Inc(P) ; // P is typed-Pointer
// do somethings
end;
2
for I:=ArrCount-1 downto 0 do
begin // I:Var is unused in below-block
Inc(P) ; // P is typed-Pointer
// do somethings
end;
3
While ArrCount>0 do
begin
Inc(P) ; // P is typed-Pointer
// do somethings
Dec(ArrCount);
end;
我对这个问题的回答可能比您预期的要平凡得多。这些变体中最快的是等待它的时间最快的运行。
完全有可能在不同的体系结构上您会发现不同的变体获胜。
还可以想象,根据循环 body 中的内容,不同的变体将获胜。
循环的 body 也很可能需要足够的时间,相比之下循环本身可以忽略不计。
总之,视情况而定。由于只有您知道 body 内部发生了什么,所以只有您可以回答具体问题。
顺便说一句,如果循环 body 没有引用循环变量,那么编译器 re-writes 升序循环就好像它是降序循环一样。所以这里实际上可能只有两种变体。事实上,这可能意味着所有三个变体都会导致相同的编译代码!
一些建议:
- 切勿在没有分析的情况下进行优化。
- 永远不要优化不是瓶颈的代码。
现在,如果你想让我猜一猜,我预测对于任何比微不足道 nop
更重要的循环 body,你会发现很难找到任何可测量的差异在这些变体之间。
我还看到您正在使用指针遍历数组。您可能会发现,如果此代码是瓶颈,并且如果循环 body 仅处理此数组迭代,则使用 arr[]
索引比指针算法更有效。但同样,它取决于很多因素,您必须分析并查看编译器生成的代码。
有趣,但是看反汇编window速度取决于天气是循环内部使用的循环变量。
1) 未使用 - 代码几乎相同:
Project17.dpr.12: for i := 0 to 3 do
0040914D B804000000 mov eax,[=10=]000004
Project17.dpr.13: Inc(j);
00409152 43 inc ebx
Project17.dpr.12: for i := 0 to 3 do
00409153 48 dec eax
00409154 75FC jnz [=10=]409152
Project17.dpr.15: for i := 3 downto 0 do
00409156 B8FCFFFFFF mov eax,$fffffffc
Project17.dpr.16: Inc(j);
0040915B 43 inc ebx
Project17.dpr.15: for i := 3 downto 0 do
0040915C 40 inc eax
0040915D 75FC jnz [=10=]40915b
2) 使用 - 第一个变体快一点,因为 xor
比 mov
快:
Project17.dpr.12: for i := 0 to 3 do
0040914D 33C0 xor eax,eax
Project17.dpr.13: Inc(j, i);
0040914F 03D8 add ebx,eax
00409151 40 inc eax
Project17.dpr.12: for i := 0 to 3 do
00409152 83F804 cmp eax,
00409155 75F8 jnz [=11=]40914f
Project17.dpr.15: for i := 3 downto 0 do
00409157 B803000000 mov eax,[=11=]000003
Project17.dpr.16: Inc(j, i);
0040915C 03D8 add ebx,eax
0040915E 48 dec eax
Project17.dpr.15: for i := 3 downto 0 do
0040915F 83F8FF cmp eax,-
00409162 75F8 jnz [=11=]40915c
您可以自己检查第三个变体。
PS: 本次测试我使用的是D2007
我有一个微优化问题。我有 3 种处理 typed-Pointer(array) 的方法。哪个更好?
1
for I:=0 to ArrCount-1 do
begin // I:Var is unused in below-block
Inc(P) ; // P is typed-Pointer
// do somethings
end;
2
for I:=ArrCount-1 downto 0 do
begin // I:Var is unused in below-block
Inc(P) ; // P is typed-Pointer
// do somethings
end;
3
While ArrCount>0 do
begin
Inc(P) ; // P is typed-Pointer
// do somethings
Dec(ArrCount);
end;
我对这个问题的回答可能比您预期的要平凡得多。这些变体中最快的是等待它的时间最快的运行。
完全有可能在不同的体系结构上您会发现不同的变体获胜。
还可以想象,根据循环 body 中的内容,不同的变体将获胜。
循环的 body 也很可能需要足够的时间,相比之下循环本身可以忽略不计。
总之,视情况而定。由于只有您知道 body 内部发生了什么,所以只有您可以回答具体问题。
顺便说一句,如果循环 body 没有引用循环变量,那么编译器 re-writes 升序循环就好像它是降序循环一样。所以这里实际上可能只有两种变体。事实上,这可能意味着所有三个变体都会导致相同的编译代码!
一些建议:
- 切勿在没有分析的情况下进行优化。
- 永远不要优化不是瓶颈的代码。
现在,如果你想让我猜一猜,我预测对于任何比微不足道 nop
更重要的循环 body,你会发现很难找到任何可测量的差异在这些变体之间。
我还看到您正在使用指针遍历数组。您可能会发现,如果此代码是瓶颈,并且如果循环 body 仅处理此数组迭代,则使用 arr[]
索引比指针算法更有效。但同样,它取决于很多因素,您必须分析并查看编译器生成的代码。
有趣,但是看反汇编window速度取决于天气是循环内部使用的循环变量。
1) 未使用 - 代码几乎相同:
Project17.dpr.12: for i := 0 to 3 do
0040914D B804000000 mov eax,[=10=]000004
Project17.dpr.13: Inc(j);
00409152 43 inc ebx
Project17.dpr.12: for i := 0 to 3 do
00409153 48 dec eax
00409154 75FC jnz [=10=]409152
Project17.dpr.15: for i := 3 downto 0 do
00409156 B8FCFFFFFF mov eax,$fffffffc
Project17.dpr.16: Inc(j);
0040915B 43 inc ebx
Project17.dpr.15: for i := 3 downto 0 do
0040915C 40 inc eax
0040915D 75FC jnz [=10=]40915b
2) 使用 - 第一个变体快一点,因为 xor
比 mov
快:
Project17.dpr.12: for i := 0 to 3 do
0040914D 33C0 xor eax,eax
Project17.dpr.13: Inc(j, i);
0040914F 03D8 add ebx,eax
00409151 40 inc eax
Project17.dpr.12: for i := 0 to 3 do
00409152 83F804 cmp eax,
00409155 75F8 jnz [=11=]40914f
Project17.dpr.15: for i := 3 downto 0 do
00409157 B803000000 mov eax,[=11=]000003
Project17.dpr.16: Inc(j, i);
0040915C 03D8 add ebx,eax
0040915E 48 dec eax
Project17.dpr.15: for i := 3 downto 0 do
0040915F 83F8FF cmp eax,-
00409162 75F8 jnz [=11=]40915c
您可以自己检查第三个变体。
PS: 本次测试我使用的是D2007