事件处理程序性能

我有性能问题。 我创建了100个新按钮,我想分配一个Click事件处理程序。 我执行此代码大约100次:

Buttons[i].Button.Click += new System.EventHandler(Button_Click); 

完成大约需要2秒。 我在同一个函数中有很多其他事件赋值,但它们只需要几毫秒来执行。 所以我已经改变了我的代码

 Buttons[i].Button.MouseUp += new System.Windows.Forms.MouseEventHandler(Button_Click); 

现在代码很快(几毫秒,就像其他代码一样)。 显然,我修改了函数“Button_click”的参数以适应新的事件要求,但没有进行其他更改。

我想知道为什么会发生这种情况。 EventHandler会慢吗? 或者我做错了什么? 还是有最好的做法?

我在C#中使用VC2010,在Windows窗体应用程序中使用.NET 4。

编辑:

现在我已经“缩小”了我的代码并将其放在那里:

  Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); Button b; for(n=0;n<100;n++) { b = new Button(); b.Location = new System.Drawing.Point(100, 0); b.Name = "btnGrid"; b.Size = new System.Drawing.Size(50, 50); b.Text = b.Name; b.UseVisualStyleBackColor = true; b.Visible = false; b.Text = ".."; b.Click += new EventHandler(this.Button_Click); //b.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Button_ClickUP); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); Log(elapsedTime, Color.Purple); 

Button_Click和Button_Click是:

  private void Button_Click(object sender, EventArgs e) { } private void Button_ClickUP(object sender, MouseEventArgs e) { } 

我将此代码放在一个按钮中,“Log”function将结果显示在备忘录中。 当我启用“Click”时,结果为01.05秒,但是当我启用“MouseUp”时,结果为00.00。

差异 – >一秒!

为什么!?

==编辑==

我使用.NET Framework 4. VS2010。 赢得XP。 我发现了这个: 如果我使用.NET 3.5或更低的速度变化:0.5秒。 一半 。 如果我在调试或发布模式下编译它不会改变。

如果我使用可执行文件而没有调试器是快速的。

所以我改变了我的问题:.NET 4比.NET 3慢吗? 与独立版本相比,为什么发布模式的工作方式不同?

非常感谢。

代码“.Click + = …”转换为“.add_Click(…)”。 “add_Click”方法可以进行一些逻辑检查。

您可以通过无需重新授权来加快速度:

 EventHandler clickHandler = this.Button_Click; foreach(Button btn in GetButtons()) { btn.Click += clicHandler; } 

编辑:

您确定,瓶颈是附加处理程序吗? 我尝试了for循环(100循环)并将eventhandler附加到Click事件,我得到了这个结果:

 /* only creation the button and attaching the handler */ button1_Click - A: 0 ms button1_Click - B: 0 ms button1_Click - A: 1 ms button1_Click - B: 0 ms button1_Click - A: 0 ms button1_Click - B: 0 ms /* creation the button, attaching the handler and add to the panel */ button2_Click - A: 223 ms button2_Click - B: 202 ms button2_Click - A: 208 ms button2_Click - B: 201 ms button2_Click - A: 204 ms button2_Click - B: 230 ms 

源代码:

  void button_Click(object sender, EventArgs e) { // do nothing } private void button1_Click(object sender, EventArgs e) { const int MAX_BUTTONS = 100; var stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); for (int i = 0; i < MAX_BUTTONS; i++) { var button = new Button(); button.Click += new EventHandler(button_Click); } stopWatch.Stop(); System.Diagnostics.Debug.WriteLine(string.Format("button1_Click - A: {0} ms", stopWatch.ElapsedMilliseconds)); stopWatch.Reset(); stopWatch.Start(); EventHandler clickHandler = this.button_Click; for (int i = 0; i < MAX_BUTTONS; i++) { var button = new Button(); button.Click += clickHandler; } stopWatch.Stop(); System.Diagnostics.Debug.WriteLine(string.Format("button1_Click - B: {0} ms", stopWatch.ElapsedMilliseconds)); } private void button2_Click(object sender, EventArgs e) { const int MAX_BUTTONS = 100; var stopWatch = new System.Diagnostics.Stopwatch(); this.panel1.Controls.Clear(); stopWatch.Start(); for (int i = 0; i < MAX_BUTTONS; i++) { var button = new Button(); button.Click += new EventHandler(button_Click); this.panel1.Controls.Add(button); } stopWatch.Stop(); System.Diagnostics.Debug.WriteLine(string.Format("button2_Click - A: {0} ms", stopWatch.ElapsedMilliseconds)); stopWatch.Reset(); this.panel1.Controls.Clear(); stopWatch.Start(); EventHandler clickHandler = this.button_Click; for (int i = 0; i < MAX_BUTTONS; i++) { var button = new Button(); button.Click += clickHandler; this.panel1.Controls.Add(button); } stopWatch.Stop(); System.Diagnostics.Debug.WriteLine(string.Format("button2_Click - B: {0} ms", stopWatch.ElapsedMilliseconds)); } 

编辑2:我尝试比较附加Click处理程序与附加MouseUp处理程序所花费的时间。 看来,附加的MouseUp事件比Click事件更快。

我认为问题将出在其他地方。 在循环期间不收集GC吗? 或者你不在那里做点什么吗?

结果:

 button1_Click - Click_A: 6 ms button1_Click - Click_B: 6 ms button1_Click - MouseUp_A: 15 ms button1_Click - MousUp_B: 7 ms button1_Click - Click_A: 16 ms button1_Click - Click_B: 7 ms button1_Click - MouseUp_A: 16 ms button1_Click - MousUp_B: 10 ms button1_Click - Click_A: 14 ms button1_Click - Click_B: 19 ms button1_Click - MouseUp_A: 27 ms button1_Click - MousUp_B: 5 ms button1_Click - Click_A: 17 ms button1_Click - Click_B: 17 ms button1_Click - MouseUp_A: 24 ms button1_Click - MousUp_B: 8 ms button1_Click - Click_A: 6 ms button1_Click - Click_B: 5 ms button1_Click - MouseUp_A: 14 ms button1_Click - MousUp_B: 7 ms button1_Click - Click_A: 14 ms button1_Click - Click_B: 9 ms button1_Click - MouseUp_A: 15 ms button1_Click - MousUp_B: 7 ms 

码:

  private void button1_Click(object sender, EventArgs e) { const int MAX_BUTTONS = 1000; var stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); for (int i = 0; i < MAX_BUTTONS; i++) { var button = new Button(); button.Click += new EventHandler(button_Click); } stopWatch.Stop(); System.Diagnostics.Debug.WriteLine(string.Format("button1_Click - Click_A: {0} ms", stopWatch.ElapsedMilliseconds)); stopWatch.Reset(); stopWatch.Start(); EventHandler clickHandler = this.button_Click; for (int i = 0; i < MAX_BUTTONS; i++) { var button = new Button(); button.Click += clickHandler; } stopWatch.Stop(); System.Diagnostics.Debug.WriteLine(string.Format("button1_Click - Click_B: {0} ms", stopWatch.ElapsedMilliseconds)); stopWatch.Start(); for (int i = 0; i < MAX_BUTTONS; i++) { var button = new Button(); button.MouseUp += new MouseEventHandler(button_MouseUp); } stopWatch.Stop(); System.Diagnostics.Debug.WriteLine(string.Format("button1_Click - MouseUp_A: {0} ms", stopWatch.ElapsedMilliseconds)); stopWatch.Reset(); stopWatch.Start(); MouseEventHandler mouseUpHandler = this.button_MouseUp; for (int i = 0; i < MAX_BUTTONS; i++) { var button = new Button(); button.MouseUp += mouseUpHandler; } stopWatch.Stop(); System.Diagnostics.Debug.WriteLine(string.Format("button1_Click - MousUp_B: {0} ms", stopWatch.ElapsedMilliseconds)); } 

编辑: add_Click方法的主体(= Click += ... )很粗糙:

 public void add_Click(EventHandler value) { this.Events.AddHandler(ClickEventIdentifier, value); } 

MouseUp事件看起来很相似。 至少两个事件都使用Events属性来保存事件的委托列表。

但是,如果我尝试了几件事情,我就无法解决事件的问题:(。。你可以在另一台计算机上重现相同的行为吗?

System.EventHandler是委托类型,因此不执行任何操作。 这不能成为性能差异的根源。
添加新的Click处理程序和新的MouseUp事件处理程序在内部是相同的。 两者都调用Events.AddHandler
在我看来,唯一的区别可能是, Click已经附加了其他事件处理程序,而MouseUp没有, MouseUp
要检查我的假设是否正确,您可以复制并粘贴两个代码片段并执行两次,并测量第一次和第二次的持续时间。

如果针对Click两次运行都很慢并且MouseUp的第二次运行速度很慢,则问题是,已经存在Click处理程序并且已经存在处理程序时添加处理程序比不存在时添加处理程序慢。

如果第一次运行Click很慢而第二次运行很快并且MouseUp两次运行都很快,那么问题是,没有现有的Click处理程序,并且当已经存在一个处理程序时添加处理程序比不存在时添加一个处理程序更快

我的回答是假设OP的观察是无副作用的。 我实际上没有测试他的结果是否可重复或合理。 我的回答只是想表明Click事件或System.EventHandler确实没有什么特别之处。

我试过这个: –

  public partial class Form1 : Form { List 

所有按钮出现并且事件似乎正确触发,事件处理程序分配太快而无法合理地测量。 在我的机器上不到一秒钟。

也许问题出在其他地方?

尝试关闭IntelliTrace。 有完全相同的症状。 不在Visual Studio下运行时速度极快,但每个btn总是增加30ms。如果在Visual Studio下运行,请点击+ = i。

所以可能IntelliTrace以某种方式挂钩到Click事件以进行详细调试。