Ask a questionAsk a question
 

Answerforeach slower than for on 360?

  • Monday, January 29, 2007 2:26 AMbagjuice Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi,
    I have been hearing on the "internets" that foreach runs slower on the XBox 360 CF because of the IEnumerators used. According to this hot book, "Effective C# (item 11)", it claims that the C# compiler 1.1+ generates different code when a foreach is used on an array. The code avoids IEnumerator and even avoids bounds check that a normal for() loop would invoke. The book, however, was written in 2004. I was hoping for a a final statement on this because I just find it hard to believe that foreach is slower on the XBox 360 and enjoy the syntax it offers.

    Thanks.

Answers

  • Monday, January 29, 2007 5:04 AMStephen Styrchak Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    When developing games, it is a good practice to avoid generating garbage. That is, to avoid allocating objects and then making them available for collection.

    Using foreach causes an enumerator to be instantiated. After the foreach loop is done, all references to that enumerator are released and it becomes eligible to be reclaimed by the garbage collector.

    The performance of using for vs. foreach is not being questioned. You may have read that foreach is faster, and that may be true, but the performance of your game will degrade if you allow garbage to be generated during gameplay. The problem again is not the for or foreach. The problem is that the garbage collector on the Xbox 360 is less efficient than the one on Windows, and doing a collection can take a long time. When you have many objects in your game, it can take longer than 1/60th of a second to do a collection. That means that you will drop frames. The more garbage you generate, the more frequently the GC will have to do a collection, and the more frequently your game will drop frames.

    So the bottom line is that you should avoid generating garbage, and using for instead of foreach is one way to do that.

    I hope that helps explain some of the seemingly conflicting information you've read.

    --Stephen

  • Monday, January 29, 2007 3:33 PMShawn Hargreaves - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Two clarifications:

    Due to an optimization in the C# compiler, foreach does not cause garbage if you use it to iterate over arrays.

    Given this code:

    int[] numbers;

    foreach (int value in numbers)
    ...

    no garbage will be created. But this optimization is quite fragile. This version:

    int[] numbers;
    IList<int> list = numbers;

    foreach (int value in list)
    ...

    will create garbage, even though it is iterating over the exact same collection. The compiler is very literal in this regard and needs it to be an actual known array presented to the foreach statement, not just an interface that might be implemented by an array. And this only applies to arrays: generic collection types like List<int> will still produce a garbage iterator.

    Also bear in mind that just because foreach creates garbage, this does not neccessarily mean you should avoid using it! I think people often get too hung up on optimisation. Fast code is good, but readable code is more important. If your program is already running fast enough, it's sometimes ok to do things the easy way, even if you know that is less efficient than it could be...

All Replies

  • Monday, January 29, 2007 5:04 AMStephen Styrchak Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    When developing games, it is a good practice to avoid generating garbage. That is, to avoid allocating objects and then making them available for collection.

    Using foreach causes an enumerator to be instantiated. After the foreach loop is done, all references to that enumerator are released and it becomes eligible to be reclaimed by the garbage collector.

    The performance of using for vs. foreach is not being questioned. You may have read that foreach is faster, and that may be true, but the performance of your game will degrade if you allow garbage to be generated during gameplay. The problem again is not the for or foreach. The problem is that the garbage collector on the Xbox 360 is less efficient than the one on Windows, and doing a collection can take a long time. When you have many objects in your game, it can take longer than 1/60th of a second to do a collection. That means that you will drop frames. The more garbage you generate, the more frequently the GC will have to do a collection, and the more frequently your game will drop frames.

    So the bottom line is that you should avoid generating garbage, and using for instead of foreach is one way to do that.

    I hope that helps explain some of the seemingly conflicting information you've read.

    --Stephen

  • Monday, January 29, 2007 3:33 PMShawn Hargreaves - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Two clarifications:

    Due to an optimization in the C# compiler, foreach does not cause garbage if you use it to iterate over arrays.

    Given this code:

    int[] numbers;

    foreach (int value in numbers)
    ...

    no garbage will be created. But this optimization is quite fragile. This version:

    int[] numbers;
    IList<int> list = numbers;

    foreach (int value in list)
    ...

    will create garbage, even though it is iterating over the exact same collection. The compiler is very literal in this regard and needs it to be an actual known array presented to the foreach statement, not just an interface that might be implemented by an array. And this only applies to arrays: generic collection types like List<int> will still produce a garbage iterator.

    Also bear in mind that just because foreach creates garbage, this does not neccessarily mean you should avoid using it! I think people often get too hung up on optimisation. Fast code is good, but readable code is more important. If your program is already running fast enough, it's sometimes ok to do things the easy way, even if you know that is less efficient than it could be...