Vec*_*vox 13 c# performance for-loop
一个关于for循环的快速简单的问题.
情况 当我突然想知道for循环实际上是如何表现时,我正在编写一些高性能代码.我知道我之前偶然发现了这一点,但不能为我的生活再次找到这个信息:/
不过,我主要担心的是限制器.说我们有:
for(int i = 0; i < something.awesome; i++)
{
// Do cool stuff
}
Run Code Online (Sandbox Code Playgroud)
问题 是something.awesome存储为内部变量还是循环不断检索某些东西.是否进行逻辑检查?我问的原因当然是因为我需要遍历很多索引的东西而且我真的不希望每次传递都有额外的函数调用开销.
然而,如果something.awesome只被召唤一次,那么我会回到我快乐的摇滚之下!:)
Dir*_*mar 21
您可以使用简单的示例程序来检查行为:
using System;
class Program
{
static int GetUpperBound()
{
Console.WriteLine("GetUpperBound called.");
return 5;
}
static void Main(string[] args)
{
for (int i = 0; i < GetUpperBound(); i++)
{
Console.WriteLine("Loop iteration {0}.", i);
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出如下:
GetUpperBound called.
Loop iteration 0.
GetUpperBound called.
Loop iteration 1.
GetUpperBound called.
Loop iteration 2.
GetUpperBound called.
Loop iteration 3.
GetUpperBound called.
Loop iteration 4.
GetUpperBound called.
Run Code Online (Sandbox Code Playgroud)
有关此行为的详细信息,请参阅C#4.0语言规范,第8.3.3节(您将在C:\ Program Files\Microsoft Visual Studio 10.0\VC#\ Specifications\1033中找到规范):
for语句执行如下:
如果存在for-initializer,则变量初始值设定项或语句表达式按其写入顺序执行.此步骤仅执行一次.
如果存在for条件,则对其进行评估.
如果for条件不存在或者评估结果为true,则控制转移到嵌入语句.当控制到达嵌入语句的结束点时(可能来自执行continue语句),for-iterator的表达式(如果有的话)按顺序计算,然后执行另一次迭代,从评估在上面的步骤中的条件.
如果存在for条件且评估结果为false,则控制转移到for语句的结束点.
如果something.awesome是一个字段,它可能每次循环访问循环,因为循环体中的某些东西可能会更新它.如果循环的主体足够简单并且不调用任何方法(除了编译器内联的方法),那么编译器可能能够证明将something.awesome的值放在寄存器中是安全的.编译器编写者过去常常负担得起这么做.
但是现在从主内存访问一个值需要很长时间,但是一旦第一次读取该值,它就会被CPU辅助.从CPU缓存中第二次读取值的速度要快得多,从寄存器读取它然后从主存储器读取它. CPU缓存比主内存快几百倍并不罕见.
现在,如果something.awesome是一个属性,那么它实际上是一个方法调用.编译器将在每次循环时调用该方法.但是,如果属性/方法只有几行代码,则它可能由编译器内联.内联是指编译器直接放入方法代码的副本而不是调用方法,因此只返回字段值的属性将与上面的字段示例相同.
当Evan没有内联属性时,它将在第一次调用之后在CPU缓存中.因此,它很复杂,或者循环很多次,第一次循环调用需要更长的时间,可能超过10倍.
在过去,它过去很容易,因为所有内存访问和CPU操作大约需要同一时间.目前,处理器缓存可以轻松地将某些内存访问和方法调用的时间更改为100倍.Profilers倾向于仍然假设所有内存访问都需要相同的时间!因此,如果您描述,您将被告知进行可能对现实世界没有任何影响的更改.
将代码更改为:
int limit = something.awesome;
for(int i = 0; i < limit; i++)
{
// Do cool stuff
}
Run Code Online (Sandbox Code Playgroud)
在某些情况下会扩散它,但也会使它更复杂.然而
int limit = myArray.length;
for(int i = 0; i < limit; i++)
{
myArray[i[ = xyn;
}
Run Code Online (Sandbox Code Playgroud)
比那慢
for(int i = 0; i < myArray.length; i++)
{
myArray[i[ = xyn;
}
Run Code Online (Sandbox Code Playgroud)
as .net每次访问时检查数组的范围,并且当循环足够简单时有逻辑删除检查.
所以最好保持代码简单明了,直到你能证明存在问题为止.通过花时间改进系统的整体设计,您可以获得更好的收益,如果您开始使用的代码很简单,这很容易做到.
| 归档时间: |
|
| 查看次数: |
1803 次 |
| 最近记录: |