Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

FYI: 'continue' in 'for' loops is VERY slow

16 views
Skip to first unread message

Roman Kuzmin

unread,
Apr 3, 2007, 7:26:41 PM4/3/07
to
Recently I have slightly refactored a script and noticed drastically
improved performance. It turned out that 'continue' in 'for' loop is VERY
slow, in my case it used to take much more time than what a loop body should
actually do.

Example:

> time { for($e=0; ; ++$e) { if ($e -ge 1000) { break } } }
TotalMilliseconds : 10.8296

> time { for($e=0; ; ++$e) { if ($e -ge 1000) { break } else {
> continue } } }
TotalMilliseconds : 170.6035

Can anybody repro\confirm this?

--
Thanks,
Roman Kuzmin


Duncan Smith

unread,
Apr 4, 2007, 2:40:48 PM4/4/07
to

Yes, it's about 20x slower for me too. Is continue an expensive
statement in other languages too such as C++? Can't say I've ever
noticed it. Does Powershell compile script blocks down to IL? I
guess you've maybe got anther script-block around the continue that
needs to be entered into, unless it's optimized away?

function time
{
[datetime]$startTime = [datetime]::now

for($e=0; ; ++$e)
{
if ($e -ge 1000)
{
break
}
}

[datetime]$endTime = [datetime]::now
($endTime - $startTime).TotalSeconds
}

function time2
{
[datetime]$startTime = [datetime]::now

for($e=0; ; ++$e)
{
if ($e -ge 1000)
{
break
}
else
{
continue
}
}

[datetime]$endTime = [datetime]::now
($endTime - $startTime).TotalSeconds

}

0.01 v 0.2

Ryan Milligan

unread,
Apr 4, 2007, 5:28:22 PM4/4/07
to
If I had to guess, I'd say it's because continue, break and return are all
implemented by throwing exceptions which are caught and handled by the
Execute() method of whichever loop control mechanism (e.g.,
Parser+DoWhileStatementNode in System.Management.Automation.dll) is running
the loop. You can see it by opening System.Management.Automation.dll (in
your Framework\v2.0.50727 folder on XP) in Reflector
(http://www.aisto.com/roeder/dotnet/) and taking a look at
Parser+FlowControlNode.Execute(). Hope this helps.

-- Ryan Milligan

"Duncan Smith" <DSmit...@googlemail.com> wrote in message
news:1175712048....@l77g2000hsb.googlegroups.com...

Roman Kuzmin

unread,
Apr 6, 2007, 2:17:51 AM4/6/07
to
If so, it looks quite dirty... and I hope this approach is temporary.

--
Thanks,
Roman Kuzmin


Duncan Smith

unread,
Apr 6, 2007, 4:49:40 AM4/6/07
to
On Apr 4, 10:28 pm, "Ryan Milligan" <Cei...@hotmail.com> wrote:
> If I had to guess, I'd say it's because continue, break and return are all
> implemented by throwing exceptions which are caught and handled by the
> Execute() method of whichever loop control mechanism (e.g.,
> Parser+DoWhileStatementNode in System.Management.Automation.dll) is running
> the loop. You can see it by opening System.Management.Automation.dll (in
> your Framework\v2.0.50727 folder on XP) in Reflector
> (http://www.aisto.com/roeder/dotnet/) and taking a look at
> Parser+FlowControlNode.Execute(). Hope this helps.
>
> -- Ryan Milligan
>

Certainly makes a good deal of sense, well found!

This reflector tool looks extremely useful, this will get a lot of
usage from me - kind of like having the MFC code to browse through.

I see that you can search for 'continue' and it finds
ContinueException in system.management.automation, but how did you
then find a reference to that tucked away in the FlowControl.Execute
method? I can't see a way to search all of the disassembled code?

Do you think there's a way that you could debug into the code that
reflector shows? Maybe by inserting a 'stop' command in a .ps1 file
(or whatever the powershell equivalent of an _asm int 3; breakpoint
call is) and then hooking it up to an instance of VS2005 for a debug
session?

Many thanks,

Duncan

Ryan Milligan

unread,
Apr 6, 2007, 11:30:16 PM4/6/07
to
Check out the "Analyzer" feature -- right click on something in the left
pane and select Analyzer (or select it and press ctrl-R), and a tree view
will open up under the code view. Expand that, and you'll see nodes like
"Depends Upon", "Used By", etc, depending on what kind of node you selected.
If you selected ContinueException, you can expand the Used By node and see
the list of methods that use the type. Select one and press space, and
you'll see it in the code view. Pretty nifty, eh?

As for debugging the code generated by Reflector, I've thought about this
myself many times. Basically, you'd need to write an extension to Reflector
that would generate a folder of source code, and a .pdb file from the .dll
that maps offsets in the IL to lines in the generated source code. I haven't
looked to see if the Reflector API provides access to all the information
you would need, but I suspect that it might. Maybe I'll get around to
looking into it some time.

-- Ryan Milligan

"Duncan Smith" <DSmit...@googlemail.com> wrote in message

news:1175849380.9...@w1g2000hsg.googlegroups.com...

0 new messages