事件处理程序性能

Red*_*dax 13 c# optimization performance event-handling winforms

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

Buttons[i].Button.Click += new System.EventHandler(Button_Click);
Run Code Online (Sandbox Code Playgroud)

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

Buttons[i].Button.MouseUp += new System.Windows.Forms.MouseEventHandler(Button_Click);
Run Code Online (Sandbox Code Playgroud)

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

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

我正在使用VC2010和C#,在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);
Run Code Online (Sandbox Code Playgroud)

Button_Click和Button_Click是:

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

    private void Button_ClickUP(object sender, MouseEventArgs e)
    {
    }
Run Code Online (Sandbox Code Playgroud)

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

差异 - >第二个!

为什么!?

==编辑==

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

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

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

非常感谢.

TcK*_*cKs 5

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

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

EventHandler clickHandler = this.Button_Click;
foreach(Button btn in GetButtons()) {
   btn.Click += clicHandler;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

你确定,瓶颈是连接处理程序吗?我尝试了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
Run Code Online (Sandbox Code Playgroud)

源代码:

    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));
    }
Run Code Online (Sandbox Code Playgroud)

编辑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
Run Code Online (Sandbox Code Playgroud)

码:

    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));
    }
Run Code Online (Sandbox Code Playgroud)

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

public void add_Click(EventHandler value) {
   this.Events.AddHandler(ClickEventIdentifier, value);
}
Run Code Online (Sandbox Code Playgroud)

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

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