Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C#中,for循环是线性的吗?_C#_Overhead - Fatal编程技术网

在C#中,for循环是线性的吗?

在C#中,for循环是线性的吗?,c#,overhead,C#,Overhead,这里我用数学术语来表示线性。例如,如果我们看一下平均值的定义,我们知道: 这就是我所说的线性。在C#中,假设我要执行以下操作: for (int i = 0; i<N; i++) { someVar[i] += i; someOtherVar[i] += i; } for(int i=0;i就复杂性而言,单循环和双循环算法都是线性的O(n)操作。但就实际性能(开销)而言,双循环版本最有可能较慢。编译器或运行时可能选择进行优化,但两个循环通常转换为: set i to 0

这里我用数学术语来表示线性。例如,如果我们看一下平均值的定义,我们知道:

这就是我所说的线性。在C#中,假设我要执行以下操作:

for (int i = 0; i<N; i++)
{
    someVar[i] += i;
    someOtherVar[i] += i;
}
for(int i=0;i就复杂性而言,单循环和双循环算法都是线性的
O(n)
操作。但就实际性能(开销)而言,双循环版本最有可能较慢。编译器或运行时可能选择进行优化,但两个循环通常转换为:

set i to 0;

a:
if i < N goto done;
set someVar[i] = someVar[i] + i;
set i = i + 1
goto a;

done:
set i to 0;

b:
if i < N goto done;
set someOtherVar[i] = someOtherVar[i] + i;
set i = i + 1;
goto b;
将i设置为0;
a:
如果我去做;
设置someVar[i]=someVar[i]+i;
设置i=i+1
转到a;
完成:
将i设置为0;
b:
如果我去做;
设置someOtherVar[i]=someOtherVar[i]+i;
设置i=i+1;
后藤b;

…这显然比一个循环的步骤多。

我做了一个IL转储,使用一个循环比使用两个循环快,因为增加“I”会产生开销。 也就是说,差别将是最小的

如果您正在处理一个更大的数据集,并且需要进一步优化它,请查看SIMD(单指令多数据)操作


我不认为“C#”(一种标准化的语言)会在这样的细节层次上强加任何东西。顺便说一下,这是C#5的标准(其他版本还在起草中):。编译器通常会根据具体情况进行一些优化,这是一个很大的增值空间。我想回答的是,一般来说,你不应该对管理费用和“成本”(不管这意味着什么)作任何假设使用一个用于循环,而使用2个用于循环。请注意,您可以使用不同级别的编译器优化进行编译,这将导致潜在的不同结果,因此在您的情况下会产生“开销”。您可以使用类似ILSpy@Pac0按“成本”我的意思是处理器开销。我写的是一个一般情况,我的实现在for循环中会有1到16次运算,我对效率很好奇。我知道C#不是最有效的语言,但它是我被迫使用的语言。我真的认为你不应该一般地假设任何事情。我们可以检查你的partics尽管如此,但我想问题的内容目前过于简化。我会进行实证分析。我建议编写比高度手工优化更有逻辑意义的代码。使用ILSpy@Pac0或dnSpy等工具可以查看生成的IL。dnSpy还可以反转存储的IL并以C#显示。如果你将鼠标悬停在IL操作代码上,它会告诉你它们是做什么的。对不起,只是对它们感兴趣。你真的编译了吗?这类东西看起来会被编译器优化吗?实际上,在性能方面,当看CPU级别时:如果这些是低级数组,不是一个聪明的抽象,并且数组足够大,那么两个循环版本的性能可能会更好,因为缓存未命中率更低,而且CPU可能会执行一些预测性抓取。但在这个级别上,除非您衡量性能,否则您永远不会知道。而且这些结果可能只适用于确切的硬件…@FilipCordas您知道C#编译器几乎不进行任何优化(缺少一些基本的表达式计算和死代码删除)?或者您的评论与“编译”不同(可能是JIT编译?)我没有编译它,这只是伪代码。我的主要观点是,如果算法需要更多的步骤才能完成,它通常会比较慢。不过,CPU是复杂的野兽,所以@PontusGagge是正确的。事实上,有时CPU甚至可以发现这两个循环可以并行运行,因为它们不会改变相同的内存区域。@FilipCordas合并两个循环是任何编译器都无法完成的,除非它能证明两个循环中的操作不会产生副作用……理论上,这对于带数组的C#来说是可能的,但对于实现自己的(可能是虚拟的)更复杂的类型来说是可能的编制索引基本上是不可能的。但是C#编译器并没有这样做-(其他语言在编译时执行积极的优化,在.Net中,所有真正的优化都是在JIT编译时完成的)请注意,查看IL与代码的最终性能几乎毫无关系……您是对的,它在某种程度上缺少性能度量,但它仍然可以告诉您编译器决定进行哪些优化(如果有的话)。
for (int i = 0; i<N; i++)
{
    someOtherVar[i] *= Math.Cos(2.0 * Math.Pi * i / N);
}
set i to 0;

a:
if i < N goto done;
set someVar[i] = someVar[i] + i;
set i = i + 1
goto a;

done:
set i to 0;

b:
if i < N goto done;
set someOtherVar[i] = someOtherVar[i] + i;
set i = i + 1;
goto b;