首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >事件处理程序性能

事件处理程序性能
EN

Stack Overflow用户
提问于 2011-05-10 14:05:27
回答 4查看 12.5K关注 0票数 13

我有表演上的问题。我创建了100个新按钮,并希望分配一个。我执行这段代码大约100次:

代码语言:javascript
复制
Buttons[i].Button.Click += new System.EventHandler(Button_Click);

它大约需要2秒才能完成。我在同一个函数中有很多其他事件分配,但它们都只需几毫秒即可执行。所以我把我的代码转换成

代码语言:javascript
复制
Buttons[i].Button.MouseUp += new System.Windows.Forms.MouseEventHandler(Button_Click);

现在代码是快速的(一些毫秒,和其他代码一样)。显然,我已经修改了函数"Button_click“的参数,以适应新的事件需求,但没有进行任何其他更改。

我想知道为什么会发生这种事。EventHandler这么慢吗?还是我做错什么了?还是有最佳做法?

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

编辑:

现在我已经“缩小”了我的代码,我把它放在那里:

代码语言:javascript
复制
            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是:

代码语言:javascript
复制
    private void Button_Click(object sender, EventArgs e)
    {            
    }

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

我把这段代码放在一个按钮中,"Log“函数在备忘录中显示结果。当我启用“单击”时,结果是01.05秒,而当我启用"MouseUp“时,结果是00.00。

差->一秒钟!

为什么!?

==编辑==

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

如果我在没有调试器的情况下使用可执行文件,则正在快速运行.

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

非常感谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-05-10 14:15:51

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

你可以在没有授权的情况下加快速度:

代码语言:javascript
复制
EventHandler clickHandler = this.Button_Click;
foreach(Button btn in GetButtons()) {
   btn.Click += clicHandler;
}

编辑:

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

代码语言:javascript
复制
/* 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

源代码:

代码语言:javascript
复制
    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:我试着比较附加单击处理程序和附加MouseUp处理程序所花费的时间。似乎没有,附加的MouseUp事件比Click事件快。

我想问题就出在别的地方。不要在循环中收集GC?或者你不在那里做其他的事?

结果:

代码语言:javascript
复制
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

代码:

代码语言:javascript
复制
    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 += ...)是粗糙的:

代码语言:javascript
复制
public void add_Click(EventHandler value) {
   this.Events.AddHandler(ClickEventIdentifier, value);
}

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

但是,如果我尝试了几件事,我就无法像你所写的那样解决这些事件的问题。你能在另一台电脑上复制同样的行为吗?

票数 5
EN

Stack Overflow用户

发布于 2011-05-10 14:15:16

System.EventHandler是一种委托类型,因此什么都不做。这不可能是性能差异的根源。

添加新的Click处理程序和新的MouseUp事件处理程序在内部是相同的。都打电话给Events.AddHandler

在我看来,唯一的区别可能是,要么Click已经附加了其他事件处理程序,而MouseUp没有或者相反。

为了检查我的假设是否正确,您可以复制和粘贴这两个代码段并执行两次,并测量第一次和第二次的持续时间。

如果Click的两次运行都比较慢,而MouseUp的第二次运行速度较慢,那么问题是,已经存在的Click处理程序已经存在,添加处理程序比不存在时添加处理程序要慢。

如果Click的第一次运行是缓慢的,第二次是快速的,而且MouseUp的两次运行都是快速的,那么问题是,没有现有的Click处理程序,并且在已经存在的情况下添加处理程序比在不存在的情况下添加处理程序要快。

我的回答假设OP的观察是无副作用的。我并没有实际测试他的结果是可复制的还是可信的。我的回答只是想说明,Click事件或System.EventHandler并没有什么特别之处。

票数 4
EN

Stack Overflow用户

发布于 2011-05-10 15:35:18

我试过这个:-

代码语言:javascript
复制
  public partial class Form1 : Form
  {
    List<Button> buttonList = new List<Button>();
    public Form1()
    {
      for (int n = 0; n < 100; n++)
      {
        Button tempButt = new Button();
        tempButt.Top = n*5;
        tempButt.Left = n * 5;
        this.Controls.Add(tempButt);
        buttonList.Add(tempButt);
      }
      var stopwatch = new Stopwatch();
      stopwatch.Start();
      foreach (Button butt in buttonList)
      {
        butt.Click += new System.EventHandler(button1_Click);
      }
      stopwatch.Stop();
      Console.WriteLine(stopwatch.ElapsedMilliseconds);
    }

    private void button1_Click(object sender, EventArgs e)
    {
      Console.WriteLine("Cheese");
    }
  }

所有按钮都会出现,事件似乎会正确启动,事件处理程序分配太快,无法合理地测量。在我的机器上还不到一秒钟。

也许问题就在别处呢?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5951301

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档