c#编译器是否优化计数属性? List=。。。 对于(int i=0;i
那么编译器是否知道列表。每次迭代都不必调用Count?你确定吗c#编译器是否优化计数属性? List=。。。 对于(int i=0;i,c#,optimization,compiler-construction,C#,Optimization,Compiler Construction,那么编译器是否知道列表。每次迭代都不必调用Count?你确定吗 List<int> list = ... for(int i = 0; i < list.Count; ++i) { ... } 这两个代码片段似乎完全不同,但这只是因为我们倾向于将for循环与while循环相比较。在这两种情况下,每次迭代都会检查变量的值。在任何一种情况下,该值都可能发生变化 通常,当同一代码的“优化”和“非优化”版本之间的行为实际上不同时,假设编译器优化了某些内容是不安
List<int> list = ...
for(int i = 0; i < list.Count; ++i)
{
...
}
这两个代码片段似乎完全不同,但这只是因为我们倾向于将for
循环与while
循环相比较。在这两种情况下,每次迭代都会检查变量的值。在任何一种情况下,该值都可能发生变化
通常,当同一代码的“优化”和“非优化”版本之间的行为实际上不同时,假设编译器优化了某些内容是不安全的。C#编译器不会进行任何类似的优化。然而,我相信JIT编译器会对数组(不可调整大小)进行优化,但不会对列表进行优化
列表的count属性可以在循环结构中更改,因此这将是一个不正确的优化。不,它不会。因为每个步骤都会计算条件。它可能比使用计数进行比较更复杂,并且允许使用任何布尔表达式:
List<int> list = new List<int>();
int i = 0;
while (list.Count <= 100)
{
list.Add(i++);
}
for(int i=0;new Random().NextDouble()<.5d;i++)
控制台写入线(i);
这取决于计数的具体实现;我从来没有注意到在列表上使用Count属性时有任何性能问题,所以我认为这是可以的 在这种情况下,您可以使用foreach节省一些打字时间
for(int i = 0; new Random().NextDouble() < .5d; i++)
Console.WriteLine(i);
List List=newlist(){0};
foreach(列表中的int项)
{
// ...
}
对于所有其他认为“Count”属性可能在循环体中发生更改的评论者:JIT优化让您能够利用正在运行的实际代码,而不是可能发生的最坏情况。总的来说,计数可能会改变。但并非所有代码中都有
因此,在海报的示例中(可能没有任何计数更改),JIT检测循环中的代码没有更改List用于保持其长度的任何内部变量是否不合理?如果它检测到list.Count
是常量,它不会将变量访问权从循环体中取出吗
我不知道JIT是否能做到这一点。但是我并没有那么快就把这个问题一笔勾销,而是简单地说了声“从不”。如果你看看Dan Tao的例子中生成的IL,你会在循环条件下看到这样一行:
List<int> list = new List<int>(){0};
foreach (int item in list)
{
// ...
}
callvirt实例int32[mscorlib]System.Collections.Generic.List`1::get_Count()
这是不可否认的证据,证明循环的每次迭代都会调用Count(即get_Count())。值得注意的是,正如没有人提到过的那样,从这样的循环来看,“Count”属性实际上会做什么,或者它可能会有什么副作用,这是不可否认的 考虑以下情况:
- 名为“Count”的属性的第三方实现可以执行它希望执行的任何代码。e、 g.返回一个我们所知道的随机数。有了列表,我们可以对它的运行方式更加自信,但是JIT如何区分这些实现呢
- 循环中的任何方法调用都可能改变Count的返回值(不仅仅是直接对集合进行“添加”,循环中调用的用户方法也可能对集合进行参与)
- 任何其他碰巧同时执行的线程也可以更改计数值
List<int> list = new List<int>(){0};
foreach (int item in list)
{
// ...
}
callvirt instance int32 [mscorlib]System.Collections.Generic.List`1<int32>::get_Count()