C#编译器无法优化for循环,与foreach相同 [英] C# compiler fails to optimize for loop same as foreach

查看:67
本文介绍了C#编译器无法优化for循环,与foreach相同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在一个网站上看到了一个引用

http://www.personalmicrocosms.com/ht...htextbox_lines

表示可以加速访问富文本框的行需要

使用foreach循环而不是for环。这对我来说绝对毫无意义,但是作者已经发布了他的代码和时间结果。 foreach

(VB和其他语言构造)在0.01%的时间内访问
富文本框中的1000行,而for则为for。循环(一个传统的C ++构造)是一个令人震惊的25秒(在不是很快的PC上)。


我使用部分源重新创建了一个测试文件作者发布的代码

并验证

两种构造之间存在显着的性能差异(尽管在我的PC上是0.01秒对3.6秒 - 仍然是

a明显的延迟)。不幸的是,没有解释为什么这个

就是这种情况,我无法看到为什么一个循环结构会为什么不同的
。用Lutz Roeder的Reflector

工具查看生成的IL代码,我发现真正的罪魁祸首不是循环结构,而是

get_Lines()函数,在foreach中拉出循环。循环和

不在for中循环代码。哪个,导致我发布关于编译器代码生成/优化的

差异的问题,是否有任何设置

可以改变这个。

有趣的是,这对于Debug和Release版本都是如此。编译器

生成的代码为循环的每次传递调用该​​函数两次

(一次用于循环索引检查,然后再次用于长度计算)。

撤出不必要的函数调用是非常基本的优化,而且我很惊讶编译器没有发现这一点。


随着IDE的智能感知和自动完成功能,for和循环
下面的代码中显示的
构造似乎有人可能实际编码的是
,当然谁会想到get_Lines

方法将是如此的性能密集。


让我想知道是否还有其他类似的问题。


谢谢,Mike L.


-------------------------------------- -------------------------------------------------- ----

//带有richtextbox控件的简单窗体,初始化为1000行

的文本(例如,#101行)等等。


private void ForLoopButton_Click(object sender,System.EventArgs e)

{

Cursor.Current = Cursors .WaitCursor;

int Len = 0;

int Start = Environment.TickCount;

for(int i = 0; i< TheRichTextBox .Lines.Length; i ++)

{

Len + = TheRichTextBox.Lines [i] .Length;

}

int ElapsedTime = Environme nt.TickCount - 开始;

ResultsTextBox.Clear();

RsultsTextBox.Text =" for loop\r\\\
\r\\\
Elapsed time = " +((double)

ElapsedTime /(double)1000.0).ToString()+" seconds \\\\\\\ nResult =" +

Len.ToString();

Cursor.Current = Cursors.Arrow;

}


private void ForEachLoopButton_Click(object sender,System.EventArgs e)

{

Cursor.Current = Cursors.WaitCursor;

int Len = 0;

int Start = Environment.TickCount;

foreach(TheRichTextBox.Lines中的String Line)

{

Len + = Line.Length;

}

int ElapsedTime = Environment.TickCount - 开始;

ResultsTextBox.Clear();

ResultsTextBox.Text =" foreach loop\r\\\
\r\\\
Elapsed time =" +((double)

ElapsedTime /(double)1000.0).ToString()+" seconds \\\\\\\ nResult =" +

Len.ToString();

Cursor.Current = Cursors.Arrow;

}


private void ForLoopButton2_Click(object sender,System.EventArgs e)

{

//性能结果现在与ForEachLoopButton_Click相同,带有更改

制作。

Cursor.Current = Cursors.WaitCursor;

int Len = 0;

int Start = Environment.TickCount;

string [] lines = TheTextBox.Lines;

for(int i = 0; i< lines.Length; i ++)

{

Len + = lines [i] .Length;

}

int ElapsedTime = Environment.TickCount - 开始;

ResultsTextBox。清除();

RsultsTextBox.Text =" for loop \\\\\\\\\\\\\\\\\\\\\\\ +((double)

ElapsedTime /(double)1000.0).ToString()+" seconds \\\\\\\ nResult =" +

Len.ToString();

Cursor.Current = Cursors.Arrow;

}

I came across a reference on a web site
(http://www.personalmicrocosms.com/ht...htextbox_lines )
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 sense
to me, but the author had posted his code and timing results. The "foreach"
(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 the
two constructs (although on my PC is was 0.01 seconds vs 3.6 seconds - still
a noticeable delay). Unfortunately, there was no explanation as to why this
was the case and I couldn''t see anything as to why one loop construct would
be different. Looking at the generated IL code with Lutz Roeder''s Reflector
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 the
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 compiler
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 I
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.

--------------------------------------------------------------------------------------------

//Simple windows form with a richtextbox control, initialized w/1000 lines
of text (e.g., "line #101", etc).

private void ForLoopButton_Click(object sender, System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
for (int i = 0; i < TheRichTextBox.Lines.Length; i++)
{
Len += TheRichTextBox.Lines[i].Length;
}
int ElapsedTime = Environment.TickCount - Start;
ResultsTextBox.Clear();
RsultsTextBox.Text = "for loop\r\n\r\nElapsed time = " + ((double)
ElapsedTime / (double) 1000.0).ToString() + " seconds\r\n\r\nResult = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

private void ForEachLoopButton_Click(object sender, System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
foreach (String Line in TheRichTextBox.Lines)
{
Len += Line.Length;
}
int ElapsedTime = Environment.TickCount - Start;
ResultsTextBox.Clear();
ResultsTextBox.Text = "foreach loop\r\n\r\nElapsed time = " + ((double)
ElapsedTime / (double) 1000.0).ToString() + " seconds\r\n\r\nResult = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

private void ForLoopButton2_Click(object sender, System.EventArgs e)
{
//Performance results now same as ForEachLoopButton_Click with the changes
made.
Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
string[] lines = TheTextBox.Lines;
for (int i = 0; i < lines.Length; i++)
{
Len += lines[i].Length;
}
int ElapsedTime = Environment.TickCount - Start;
ResultsTextBox.Clear();
RsultsTextBox.Text = "for loop\r\n\r\nElapsed time = " + ((double)
ElapsedTime / (double) 1000.0).ToString() + " seconds\r\n\r\nResult = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

推荐答案



" Mike Lansdaal" <毫升***** @ newsgroup.nospam>在消息中写道

news:70 ********************************** @ microsof t.com ...

"Mike Lansdaal" <ml*****@newsgroup.nospam> wrote in message
news:70**********************************@microsof t.com...
我在一个网站上看到了一个引用

http://www.personalmicrocosms.com/ht...htextbox_lines )表示可以加快对富文本框的访问速度你需要使用foreach的行。循环而不是for环。这对我来说绝对没有任何意义,但是作者已经发布了他的代码和时间结果。
" foreach" (一个VB和其他语言构造)在0.01%的时间内访问富文本框中的1000行
,而for则为for。循环(一个传统的C ++构造)是一个惊人的25秒(在一台不是很快的PC上)。

我使用作者发布的部分源代码重新创建了一个测试文件。 >并验证两个结构的
之间存在显着的性能差异(尽管在我的PC上是0.01秒对3.6秒 -
仍有明显的延迟)。不幸的是,没有解释为什么
就是这种情况,我无法看到为什么一个循环构造
会有所不同。用Lutz Roeder的
Reflector工具查看生成的IL代码,我发现真正的罪魁祸首不是循环结构,而是
get_Lines()函数被拉出循环中的 ;的foreach"循环
而不是for循环代码。哪个,导致我发布关于
这个问题的编译器代码生成/优化的差异,是否有任何
设置可以改变这个。

有趣的是,这两个都是如此调试和发布版本。
编译器生成的代码为循环的每次传递调用该​​函数两次
(一次用于循环索引检查,然后再次用于长度计算)。
拉出不必要的函数调用是相当的基本优化,
我很惊讶编译器没有检测到这一点。

使用IDE的智能感知和自动完成功能,for和下面的代码中显示的循环
构造似乎是某人可能真正编写代码的东西,当然谁会想到
get_Lines方法会如此高性能。

让我想知道是否还有其他类似的问题。

谢谢,Mike L.

------------ -------------------------------------------------- ------------
------------------
//带有richtextbox控件的简单窗体,初始化为w / 1000行
文本(例如,#101行等)。

private void ForLoopButton_Click(object sender,System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
for(int i = 0; i< TheRichTextBox.Lines.Length; i ++ )
{Len / = TheRichTextBox.Lines [i] .Length;
}
int ElapsedTime = Environment.TickCount - Start;
ResultsTextBox.Clear();
RsultsTextBox.Text =" for loop \\ \\ n \ n \\ n \\ n \\ n \\ n \\ n经过的时间=" +((double)
ElapsedTime /(double)1000.0).ToString()+" seconds \\\\\\\ nResult =" +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}
私有void ForEachLoopButton_Click(对象发送者,System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
foreach(TheRichTextBox.Lines中的String Line)
{
Len + = Line.Length;
}
int ElapsedTime = Environment.TickCount - 开始;
ResultsTextBox.Clear();
ResultsTextBox.Text = foreach loop \\\\\\\\\\\\\\\\\\\\ +((double)
ElapsedTime /(double)1000.0).ToString()+" seconds \\\\\\\ nResult =" +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}
私有空ForLoopButton2_Click(对象发送者,System.EventArgs e)
{
//性能结果现在与ForEachLoopButton_Click相同,并且更改了

Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
string [] lines = TheTextBox.Lines;
for(int i = 0; i< lines.Length; i ++)
{Len / + Len + = lines [i] .Length;
}
int ElapsedTime = Environment.TickCount - Start;
ResultsTextBox.Clear();
RsultsTextBox.Text =" for loop\ r \\\\\ n经过的时间=" +((double)
ElapsedTime /(double)1000.0).ToString()+" seconds \\\\\\\ nResult =" +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}
I came across a reference on a web site
(http://www.personalmicrocosms.com/ht...htextbox_lines ) 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 sense to me, but the author had posted his code and timing results. The "foreach" (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 the two constructs (although on my PC is was 0.01 seconds vs 3.6 seconds - still a noticeable delay). Unfortunately, there was no explanation as to why this was the case and I couldn''t see anything as to why one loop construct would be different. Looking at the generated IL code with Lutz Roeder''s Reflector 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 the 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 compiler 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 I 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.

-------------------------------------------------------------------------- ------------------
//Simple windows form with a richtextbox control, initialized w/1000 lines
of text (e.g., "line #101", etc).

private void ForLoopButton_Click(object sender, System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
for (int i = 0; i < TheRichTextBox.Lines.Length; i++)
{
Len += TheRichTextBox.Lines[i].Length;
}
int ElapsedTime = Environment.TickCount - Start;
ResultsTextBox.Clear();
RsultsTextBox.Text = "for loop\r\n\r\nElapsed time = " + ((double)
ElapsedTime / (double) 1000.0).ToString() + " seconds\r\n\r\nResult = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

private void ForEachLoopButton_Click(object sender, System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
foreach (String Line in TheRichTextBox.Lines)
{
Len += Line.Length;
}
int ElapsedTime = Environment.TickCount - Start;
ResultsTextBox.Clear();
ResultsTextBox.Text = "foreach loop\r\n\r\nElapsed time = " + ((double)
ElapsedTime / (double) 1000.0).ToString() + " seconds\r\n\r\nResult = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}

private void ForLoopButton2_Click(object sender, System.EventArgs e)
{
//Performance results now same as ForEachLoopButton_Click with the changes
made.
Cursor.Current = Cursors.WaitCursor;
int Len = 0;
int Start = Environment.TickCount;
string[] lines = TheTextBox.Lines;
for (int i = 0; i < lines.Length; i++)
{
Len += lines[i].Length;
}
int ElapsedTime = Environment.TickCount - Start;
ResultsTextBox.Clear();
RsultsTextBox.Text = "for loop\r\n\r\nElapsed time = " + ((double)
ElapsedTime / (double) 1000.0).ToString() + " seconds\r\n\r\nResult = " +
Len.ToString();
Cursor.Current = Cursors.Arrow;
}




太棒了!我不知道。我当然希望有人能够解释这个。


/ Fredrik



Amazing! I had no idea. I sure hope someone is capable of explaining this.

/ Fredrik




嗨/>

我在这里发现了一些可以解释这个问题的东西:
http://www.codeproject.com/csharp/foreach.asp

/ Fredrik

Hi

I found something here that may explain this problem:
http://www.codeproject.com/csharp/foreach.asp

/ Fredrik



" Mike Lansdaal" <毫升***** @ newsgroup.nospam>在消息中写道

news:70 ********************************** @ microsof t.com ...

"Mike Lansdaal" <ml*****@newsgroup.nospam> wrote in message
news:70**********************************@microsof t.com...
我在一个网站上看到了一个引用
http://www.personalmicrocosms.com/ht...htextbox_lines
表示可以加快对富文本的访问速度您需要使用foreach框的行'循环而不是for环。这对我来说绝对没有意义,但是作者已经发布了他的代码和时间结果。
foreach
(VB和其他语言构造)在富文本框中访问1000行
是0.01秒,而for是for。循环(一个传统的C ++构造)是一个惊人的25秒(在一台不是很快的PC上)。

我使用作者发布的部分源代码重新创建了一个测试文件。 >并确认
两个构造之间存在显着的性能差异(虽然在我的PC上是0.01秒对3.6秒 -
仍然是明显的延迟)。不幸的是,没有解释为什么
这是
,我无法看到为什么一个循环构造
会有所不同。用Lutz Roeder的反射器
工具查看生成的IL代码,我发现真正的罪魁祸首不是循环结构,而是
get_Lines()函数被拉出循环在foreach中循环

不在for中循环代码。哪个,导致我发布这个关于编译器代码生成/优化的差异的问题,是否有任何
设置可以改变这个。
I came across a reference on a web site
(http://www.personalmicrocosms.com/ht...htextbox_lines
)
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
sense
to me, but the author had posted his code and timing results. The
"foreach"
(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
the
two constructs (although on my PC is was 0.01 seconds vs 3.6 seconds -
still
a noticeable delay). Unfortunately, there was no explanation as to why
this
was the case and I couldn''t see anything as to why one loop construct
would
be different. Looking at the generated IL code with Lutz Roeder''s
Reflector
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
the
differences in complier code generation/optimization and is there any
setting
that can change this.




啊。这不是编译器问题。这是一个属性问题。


get_Lines()很贵。谁知道?这是属性的问题:你

永远不知道他们运行了多少代码。


无论如何,试试这个:

string [] lines = TheRichTextBox.Lines;

for(int i = 0; i< lines.Length; i ++)

{

Len + = lines [i] .Length;

}


它应该类似于foreach案例。


David



Ah. It''s not a compiler problem. It''s a property problem.

get_Lines() is expensive. Who Knew? That''s the problem with properties: you
never know how much code they run.

Anyway, try this:

string[] lines = TheRichTextBox.Lines;
for (int i = 0; i < lines.Length; i++)
{
Len += lines[i].Length;
}

It should be similar to the foreach case.

David


这篇关于C#编译器无法优化for循环,与foreach相同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆