其中一个for循环比另一个更快?

时间:2010-12-03 09:54:16

标签: c#

for (var keyValue = 0; keyValue < dwhSessionDto.KeyValues.Count; keyValue++)
{...}


var count = dwhSessionDto.KeyValues.Count;
for (var keyValue = 0; keyValue < count; keyValue++)
{...}

我知道两者之间存在差异,但其中一种比另一种更快?我认为第二个更快。

7 个答案:

答案 0 :(得分:39)

是的,第一个版本很多更慢。毕竟,我假设你正在处理这样的类型:

public class SlowCountProvider
{
    public int Count
    {
        get
        {
            Thread.Sleep(1000);
            return 10;
        }
    }
}

public class KeyValuesWithSlowCountProvider
{
    public SlowCountProvider KeyValues
    {
        get { return new SlowCountProvider(); }
    }
}

在这里,你的第一个循环需要大约10秒钟,而你的第二个循环需要大约1秒钟。

当然,您可能会认为您使用此代码的假设是不合理的 - 但我的观点是正确的答案将取决于所涉及的类型,而问题并未说明这些类型是什么。< / p>

现在,如果你实际上处理一种类型,其中访问KeyValuesCount便宜(很可能),我不希望有太多区别。请注意,我几乎总是喜欢尽可能使用foreach

foreach (var pair in dwhSessionDto.KeyValues)
{
    // Use pair here
}

这样你永远不需要计数。但是,你还没有说过你在循环中想做什么。 (提示:要获得更有用的答案,provide more information。)

答案 1 :(得分:6)

它取决于计算dwhSessionDto.KeyValues.Count的难度,如果它只是指向int的指针,那么每个版本的速度将是相同的。但是,如果需要计算Count值,则每次都会计算它,因此会妨碍性能。

编辑 - 继承了一些代码,以证明条件总是经过重新评估

public class Temp
{
    public int Count { get; set; }
}

static void Main(string[] args)
{
    var t = new Temp() {Count = 5};
    for (int i = 0; i < t.Count; i++)
    {
        Console.WriteLine(i);
        t.Count--;
    }
    Console.ReadLine();
}

输出为0,1,2 - 仅!

答案 2 :(得分:1)

请参阅评论,了解答案错误的原因。

如果存在差异,那就相反:事实上,第一个可能会更快。那是因为编译器识别出你正在从0迭代到数组的末尾,因此它可以忽略循环中的边界检查(即当你访问dwhSessionDTo.KeyValues[i]时)。

但是,我相信编译器只将此优化应用于数组,因此这里可能没有区别。

答案 3 :(得分:1)

如果不知道dwhSessionDto.KeyValues.Count和循环体的实现,就不可能说。

假设全局变量bool foo = false;,然后执行以下实现:

/* Loop body... */
{
    if(foo) Thread.Sleep(1000);
}

/* ... */
public int Count
{
    get
    {
        foo = !foo;            
        return 10;
    }
}
/* ... */

现在,第一个循环的速度大约是第二个循环的两倍; D

然而,假设非愚蠢的实施,第二个确实更有可能更快。

答案 4 :(得分:0)

没有。这两个循环之间没有性能差异。使用JITCode Optimization,它没有任何区别。

答案 5 :(得分:0)

没有区别,但为什么你认为存在差异,请你发表你的发现吗?

如果您在使用反射器

的字典中看到插入项的实现
private void Insert(TKey key, TValue value, bool add)
{
int freeList;
if (key == null)
{
    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
if (this.buckets == null)
{
    this.Initialize(0);
}
int num = this.comparer.GetHashCode(key) & 0x7fffffff;
int index = num % this.buckets.Length;
for (int i = this.buckets[index]; i >= 0; i = this.entries[i].next)
{
    if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
    {
        if (add)
        {
            ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
        }
        this.entries[i].value = value;
        this.version++;
        return;
    }
}
if (this.freeCount > 0)
{
    freeList = this.freeList;
    this.freeList = this.entries[freeList].next;
    this.freeCount--;
}
else
{
    if (this.count == this.entries.Length)
    {
        this.Resize();
        index = num % this.buckets.Length;
    }
    freeList = this.count;
    this.count++;
}
this.entries[freeList].hashCode = num;
this.entries[freeList].next = this.buckets[index];
this.entries[freeList].key = key;
this.entries[freeList].value = value;
this.buckets[index] = freeList;
this.version++;

}

Count是此类的内部成员,每个项目都会在项目中插入

所以我相信没有任何区别。

答案 6 :(得分:0)

第二个版本有时会更快。关键是在每次迭代后重新评估条件,因此,例如, “Count”的getter实际上会对IEnumerable中的元素进行计数,或者对数据库/ etc进行interog,这会减慢速度。

所以我要说如果你不影响“for”中“Count”的值,那么第二个版本会更安全。