For vs. For Each

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Chad Z. Hower aka Kudzu

    #61
    Re: For vs. For Each

    "Fredrik Wahlgren" <fredrik.p.wahl gren@mailbox.sw ipnet.se> wrote in
    news:##fpK$rEFH A.228@TK2MSFTNG P15.phx.gbl:[color=blue]
    > Makes me wonder if there are any other gotchas like this.[/color]

    This is well known. Its because many (but not all) list type items are
    maintained internally without an index (or other, such as linked items) and
    the for loop requires access by index, in which such structures access by
    index is slow.


    --
    Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
    "Programmin g is an art form that fights back"

    Empower ASP.NET with IntraWeb

    Comment

    • Patrice

      #62
      Re: For vs. For Each

      A possible explanation would be :
      - With for, it has to find out the element from its index in each loop.
      - With for each it just has to locate the next element from the current one
      which may be easier in some cases (such as a linked list).

      It could be interesting to see if there is a difference depending on the
      nature fo the enumerated collection.

      Patrice
      --

      "Fredrik Wahlgren" <fredrik.p.wahl gren@mailbox.sw ipnet.se> a écrit dans le
      message de news:%23%23fpK$ rEFHA.228@TK2MS FTNGP15.phx.gbl ...[color=blue]
      > Snipped from this ng:
      >
      > "I came across a reference on a web site
      >[/color]
      (http://www.personalmicrocosms.com/ht...htextbox_lines )[color=blue]
      > that said to speed up access to a rich text box's lines that you needed to
      > use a "foreach" loop instead of a "for" loop. This made absolutely no[/color]
      sense[color=blue]
      > to me, but the author had posted his code and timing results. The[/color]
      "foreach"[color=blue]
      > (a VB and other languages construct) was 0.01 seconds to access 1000 lines
      > in
      > rich text box, whereas the "for" loop (a traditional C++ construct) was an
      > astounding 25 seconds (on a not very fast PC).
      >
      > I recreated a test file using the partial source code posted by the author
      > and verified that there is a SIGNIFICANT performance difference between[/color]
      the[color=blue]
      > two constructs (although on my PC is was 0.01 seconds vs 3.6 seconds -[/color]
      still[color=blue]
      > a noticeable delay). Unfortunately, there was no explanation as to why[/color]
      this[color=blue]
      > was the case and I couldn't see anything as to why one loop construct[/color]
      would[color=blue]
      > be different. Looking at the generated IL code with Lutz Roeder's[/color]
      Reflector[color=blue]
      > tool, I see that the real culprit is not the loop structure but the
      > get_Lines() function that is pulled out of the loop in the "foreach" loop
      > and
      > not in the "for" loop code. Which, leads to me post this question about[/color]
      the[color=blue]
      > differences in complier code generation/optimization and is there any
      > setting
      > that can change this.
      >
      > Interestingly, this is true for both Debug and Release builds. The[/color]
      compiler[color=blue]
      > generated code that called that function twice for each pass of the loop
      > (once for the loop index check and then again for the length calculation).
      > Pulling out unneccessary function calls is pretty basic optimization, and[/color]
      I[color=blue]
      > surprised that the compiler didn't detect this.
      >
      > With the IDE's intellisense and auto completion features, the "for" loop
      > construct shown in the code below seems like something that someone might
      > actually code up, and of course who would have figured out that the
      > get_Lines
      > method would be so performance intensive.
      >
      > Makes me wonder if there are any other gotchas like this.
      >
      > Thanks, Mike L.
      >
      > --------------------------------------------------------------------------[/color]
      --[color=blue]
      > ----------------
      >
      > //Simple windows form with a richtextbox control, initialized w/1000 lines
      > of text (e.g., "line #101", etc).
      >
      > private void ForLoopButton_C lick(object sender, System.EventArg s e)
      > {
      > Cursor.Current = Cursors.WaitCur sor;
      > int Len = 0;
      > int Start = Environment.Tic kCount;
      > for (int i = 0; i < TheRichTextBox. Lines.Length; i++)
      > {
      > Len += TheRichTextBox. Lines[i].Length;
      > }
      > int ElapsedTime = Environment.Tic kCount - Start;
      > ResultsTextBox. Clear();
      > RsultsTextBox.T ext = "for loop\r\n\r\nEla psed time = " + ((double)
      > ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
      > Len.ToString();
      > Cursor.Current = Cursors.Arrow;
      > }
      >
      > private void ForEachLoopButt on_Click(object sender, System.EventArg s e)
      > {
      > Cursor.Current = Cursors.WaitCur sor;
      > int Len = 0;
      > int Start = Environment.Tic kCount;
      > foreach (String Line in TheRichTextBox. Lines)
      > {
      > Len += Line.Length;
      > }
      > int ElapsedTime = Environment.Tic kCount - Start;
      > ResultsTextBox. Clear();
      > ResultsTextBox. Text = "foreach loop\r\n\r\nEla psed time = " + ((double)
      > ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
      > Len.ToString();
      > Cursor.Current = Cursors.Arrow;
      > }
      >
      > private void ForLoopButton2_ Click(object sender, System.EventArg s e)
      > {
      > //Performance results now same as ForEachLoopButt on_Click with the changes
      > made.
      > Cursor.Current = Cursors.WaitCur sor;
      > int Len = 0;
      > int Start = Environment.Tic kCount;
      > string[] lines = TheTextBox.Line s;
      > for (int i = 0; i < lines.Length; i++)
      > {
      > Len += lines[i].Length;
      > }
      > int ElapsedTime = Environment.Tic kCount - Start;
      > ResultsTextBox. Clear();
      > RsultsTextBox.T ext = "for loop\r\n\r\nEla psed time = " + ((double)
      > ElapsedTime / (double) 1000.0).ToStrin g() + " seconds\r\n\r\n Result = " +
      > Len.ToString();
      > Cursor.Current = Cursors.Arrow;
      > }"
      >
      > "Othman Kinani" <OthmanKinani@d iscussions.micr osoft.com> wrote in message
      > news:152CA049-9926-431B-B42E-1D6F900BCB4A@mi crosoft.com...[color=green]
      > >
      > >
      > > "anonymous@disc ussions.microso ft.com" wrote:
      > >[color=darkred]
      > > > Is there a performance difference between this:
      > > >
      > > > \\\
      > > > Dim i As Integer
      > > > For i = 0 to myObject.Contro ls.Count - 1
      > > > myObject.Contro ls(i) = ...
      > > > Next
      > > > ///
      > > >
      > > > and this:
      > > >
      > > > \\\
      > > > Dim ctl As Control
      > > > For Each ctl In myObject.Contro ls
      > > > ctl = ...
      > > > Next
      > > > ///
      > > >
      > > > Or is For Each just "prettier"?
      > > >
      > > > Thanks,
      > > >
      > > > Eric
      > > >
      > > >
      > > >[/color][/color]
      >
      >[/color]


      Comment

      • James Curran

        #63
        Re: For vs. For Each

        That's a hard question to answer:

        For arrays/vectors/ILists --- collections which can be directly indexed,
        it's close to a wash. (* but see below)

        For other kinds of collections (hashtables, linked-lists) -- collections
        which aren't or aren't easily indexed, foreach would be the faster, and
        possibly the only, way to iterator through.

        In some cases, bad coding just throws everything out the window, such as
        the page Fredrik cites, where in the for(), he's calling "i <
        TheRichTextBox. Lines.Length" each time through the loop -- except
        "TheRichTextBox .Lines" builds and return s string[] each time it's called,
        so 99% of the time of loop is being wasted.

        And finally, the (*) note I mentioned above: The guys writing the C#
        compiler knew that
        for (int i = 0; i< coll.Length; ++i)
        is a very common idiom in C/C++/C# code, and had the compiler recognize and
        optimize it, so right now, for()s in the specific pattern are faster, but
        with the next release of the C# compiler, maybe they'll get around to
        optimizing foreachs.....

        "Othman Kinani" <OthmanKinani@d iscussions.micr osoft.com> wrote in message
        news:152CA049-9926-431B-B42E-1D6F900BCB4A@mi crosoft.com...[color=blue]
        >
        >
        > "anonymous@disc ussions.microso ft.com" wrote:
        >[color=green]
        > > Is there a performance difference between this:
        > >
        > > \\\
        > > Dim i As Integer
        > > For i = 0 to myObject.Contro ls.Count - 1
        > > myObject.Contro ls(i) = ...
        > > Next
        > > ///
        > >
        > > and this:
        > >
        > > \\\
        > > Dim ctl As Control
        > > For Each ctl In myObject.Contro ls
        > > ctl = ...
        > > Next
        > > ///
        > >
        > > Or is For Each just "prettier"?
        > >
        > > Thanks,
        > >
        > > Eric
        > >
        > >
        > >[/color][/color]


        Comment

        • Jon Skeet [C# MVP]

          #64
          Re: For vs. For Each

          James Curran <jamescurran@mv ps.org> wrote:

          <snip>
          [color=blue]
          > And finally, the (*) note I mentioned above: The guys writing the C#
          > compiler knew that
          > for (int i = 0; i< coll.Length; ++i)
          > is a very common idiom in C/C++/C# code, and had the compiler recognize and
          > optimize it, so right now, for()s in the specific pattern are faster, but
          > with the next release of the C# compiler, maybe they'll get around to
          > optimizing foreachs.....[/color]

          Just a point of pedantry really, but I don't believe it's the C#
          compiler at all - I believe it's the JIT compiler. That's good, as it
          means that VB.NET and MC++ get the same advantages, so long as the JIT
          recognises the code for the same kind of loop.

          --
          Jon Skeet - <skeet@pobox.co m>
          Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

          If replying to the group, please do not mail me too

          Comment

          • Lasse VÃ¥gsæther Karlsen

            #65
            Re: For vs. For Each

            Othman Kinani wrote:[color=blue]
            >
            > "anonymous@disc ussions.microso ft.com" wrote:
            >
            >[color=green]
            >>Is there a performance difference between this:[/color][/color]
            <snip for vs. foreach)

            It depends on the collection you iterate over.

            Possible issues that might have an impact:

            - does .Length/.Count read the number from an internal variable or does
            it need to do a lengthy operation to determine it (ie. split up a big
            string into separate lines and count them)
            - can [index] grab the correct value from an internal list or does it
            need to do the same type of work as the .Length/.Count operation does ?
            - how is the enumerator implemented, does it pre-cache a list (like
            splitting up the text) and simply iterate through the results, or does
            it have to compute the next result in some way each time ?

            There's probably many more issues that will have an impact on for vs.
            foreach, so the best way to determine this is to read the documentation
            for the specific collection class you're using and/or profile it.

            Things to consider:
            - [index] calls a method, which might call a method on an internal object
            - foreach constructs an object for the enumerator

            Wether these things matter in your case, depends on the collection you use.

            --
            Lasse Vågsæther Karlsen

            mailto:lasse@vk arlsen.no
            PGP KeyID: 0x0270466B

            Comment

            • Stefan Simek

              #66
              Re: For vs. For Each

              Just my 2c...

              The Lines property of TextBox/RichTextBox returns a string[]. This is NOT
              the native format for the TextBox, so every time you get the Lines property,
              a new array is populated with the contents of the TextBox.

              When you use foreach, the code becomes something like this:

              string[] lines = textBox.Lines;
              IEnumerator e = lines.GetEnumer ator();
              while (e.MoveNext())
              {
              string current = (string) e.Current;

              ...
              }

              See? You retrieve the Lines array only once, but when using it in a for
              loop, then you build the array in every single iteration! (and maybe more
              than once).

              for (int i = 0; i < textBox.Lines.L ength; i++) // first time - each loop
              {
              string current = textBox.Lines[i]; // second time - each loop
              }

              The compiler certainly can't take the textBox.Lines access out of the loop,
              because it cannot be sure that the Lines property returns always the same
              array.

              If the Lines property was something like TextBoxLineColl ection, then the
              performance would be probably more or less the same (depending on how the
              collection would be implemented).

              HTH,
              Stefan


              "Lasse Vagsather Karlsen" <lasse@vkarlsen .no> wrote in message
              news:%23rRn%23c AFFHA.3244@TK2M SFTNGP15.phx.gb l...[color=blue]
              > Othman Kinani wrote:[color=green]
              >>
              >> "anonymous@disc ussions.microso ft.com" wrote:
              >>
              >>[color=darkred]
              >>>Is there a performance difference between this:[/color][/color]
              > <snip for vs. foreach)
              >
              > It depends on the collection you iterate over.
              >
              > Possible issues that might have an impact:
              >
              > - does .Length/.Count read the number from an internal variable or does it
              > need to do a lengthy operation to determine it (ie. split up a big string
              > into separate lines and count them)
              > - can [index] grab the correct value from an internal list or does it need
              > to do the same type of work as the .Length/.Count operation does ?
              > - how is the enumerator implemented, does it pre-cache a list (like
              > splitting up the text) and simply iterate through the results, or does it
              > have to compute the next result in some way each time ?
              >
              > There's probably many more issues that will have an impact on for vs.
              > foreach, so the best way to determine this is to read the documentation
              > for the specific collection class you're using and/or profile it.
              >
              > Things to consider:
              > - [index] calls a method, which might call a method on an internal object
              > - foreach constructs an object for the enumerator
              >
              > Wether these things matter in your case, depends on the collection you
              > use.
              >
              > --
              > Lasse Vagsather Karlsen
              > http://www.vkarlsen.no/
              > mailto:lasse@vk arlsen.no
              > PGP KeyID: 0x0270466B[/color]


              Comment

              Working...