简体   繁体   English

这些for循环之一比另一个循环快吗?

[英]Is one of these for loops faster than the other?

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


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

I know there's a difference between the two, but is one of them faster than the other? 我知道两者之间有区别,但是其中一个比另一个快吗? I would think the second is faster. 我认为第二个更快。

Yes, the first version is much slower. 是的,第一个版本是慢得多 After all, I'm assuming you're dealing with types like this: 毕竟,我假设您正在处理这样的类型:

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

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

Here, your first loop will take ~10 seconds, whereas your second loop will take ~1 second. 在这里,您的第一个循环大约需要10秒,而您的第二个循环大约需要1秒。

Of course, you might argue that the assumption that you're using this code is unjustified - but my point is that the right answer will depend on the types involved, and the question doesn't state what those types are. 当然,您可能会认为使用此代码的假设是不合理的-但我的观点是正确的答案将取决于所涉及的类型,而问题并没有说明这些类型是什么。

Now if you're actually dealing with a type where accessing KeyValues and Count is cheap (which is quite likely) I wouldn't expect there to be much difference. 现在,如果您实际上正在处理访问KeyValuesCount便宜的类型(这很有可能),那么我希望不会有太大的区别。 Mind you, I'd almost always prefer to use foreach where possible: 提醒您,我几乎总是喜欢在可能的地方使用foreach

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

That way you never need the count. 这样,您就不需要计数了。 But then, you haven't said what you're trying to do inside the loop either. 但是然后,您也没有说您要在循环中执行的操作。 (Hint: to get more useful answers, provide more information .) (提示:要获得更多有用的答案,请提供更多信息 。)

it depends how difficult it is to compute dwhSessionDto.KeyValues.Count if its just a pointer to an int then the speed of each version will be the same. 它取决于计算dwhSessionDto.KeyValues.Count如果它只是一个指向int的指针),则每个版本的速度将相同。 However, if the Count value needs to be calculated, then it will be calculated every time, and therefore impede perfomance. 但是,如果需要计算Count值,则每次都会计算该值,因此会妨碍性能。

EDIT -- heres some code to demonstrate that the condition is always re-evaluated 编辑 -这是一些代码来证明条件总是被重新评估

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();
}

The output is 0, 1, 2 - only ! 输出为0、1、2-仅!

See comments for reasons why this answer is wrong. 有关此答案错误的原因,请参见评论。

If there is a difference, it's the other way round: Indeed, the first one might be faster. 如果存在差异,则相反:实际上, 一个可能更快。 That's because the compiler recognizes that you are iterating from 0 to the end of the array, and it can therefore elide bounds checks within the loop (ie when you access dwhSessionDTo.KeyValues[i] ). 那是因为编译器认识到您正在从0迭代到数组的末尾,因此它可以dwhSessionDTo.KeyValues[i]循环内的边界检查(即,当您访问dwhSessionDTo.KeyValues[i] )。

However, I believe the compiler only applies this optimization to arrays so there probably will be no difference here. 但是,我相信编译器只会将此优化应用于数组,因此这里可能没有什么区别。

It is impossible to say without knowing the implementation of dwhSessionDto.KeyValues.Count and the loop body. 不知道dwhSessionDto.KeyValues.Count和循环体的实现是不可能的。

Assume a global variable bool foo = false; 假设全局变量bool foo = false; and then following implementations: 然后执行以下操作:

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

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

Now, the first loop will perform approximately twice as fast as the second ;D 现在,第一个循环的执行速度大约是第二个; D的两倍

However, assuming non-moronic implementation, the second one is indeed more likely to be faster. 但是,假设采用非常规的实现方式,那么第二种实现的速度确实会更快。

No. There is no performance difference between these two loops. 否。这两个循环之间没有性能差异。 With JIT and Code Optimization , it does not make any difference. 使用JITCode Optimization ,没有任何区别。

There is no difference but why you think that thereis difference , can you please post your findings? 没有区别,但是为什么您认为有区别,您可以发表您的发现吗?

if you see the implementation of insert item in Dictionary using reflector 如果看到使用反射器在Dictionary中执行插入项

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 is a internal member to this class which is incremented each item you insert an item into dictionary Count是此类的内部成员,您将每一项插入字典时都会增加该类的内部成员

so i beleive that there is no differenct at all. 所以我相信根本没有区别。

The second version can be faster, sometimes. 有时,第二个版本可能会更快。 The point is that the condition is reevaluated after every iteration, so if eg the getter of "Count" actually counts the elements in an IEnumerable, or interogates a database /etc, this will slow things down. 关键是条件在每次迭代后都会重新评估,因此,例如,如果“ Count”的获取器实际上对IEnumerable中的元素进行计数,或者对数据库/ etc进行查询,这将使速度变慢。

So I'd say that if you dont affect the value of "Count" in the "for", the second version is safer. 因此,我想说的是,如果您不影响“ for”中“ Count”的值,则第二个版本更安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM