且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

事件处理程序性能

更新时间:2023-02-27 15:12:26

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



您可以稍微加快一点,不需要代理娱乐:

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

编辑:



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

  / *只创建按钮并附加处理程序* / 
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

/ *创建按钮,附加处理程序并添加到面板* /
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(); (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; (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(); (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; (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循环中不要收集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对象发件人,EventArgs e){
const int MAX_BUTTONS = 1000;
var stopWatch = new System.Diagnostics.Stopwatch();

stopWatch.Start(); (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; (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(); (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; (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 方法(= 点击+ = ... )粗糙:

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

MouseUp事件看起来会相似。至少两个事件使用事件属性来保存事件的代理列表。



但是,如果我尝试了几件事情($)
您可以在另一台电脑上再现相同的行为吗?


I have a performance problem. I create 100 new buttons and I want to assign an Click Event Handler. I execute this code for about 100 times:

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

It takes about 2sec to complete. I have a lot of other event assignments in the same function, but they all take only some millisecond to execute. So I have transformed my code in

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

Now the code is fast (some millisecond, like the others). Obviously I have modified the parameters of the function "Button_click" to fit the new event requirements, but no other changes were made.

I am wondering why this could happen. Is EventHandler that slow? Or am I doing something wrong? Or is there a best practice?

I am using VC2010 with C#, using .NET 4 in a Windows Form application.

EDIT:

Now I have "minified" my code and I put it there:

            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 and Button_Click are:

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

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

I put this code in a button and the "Log" function display the result in a memo. When I enable "Click" the result is 01.05 sec, but when I enable "MouseUp" the result is 00.00.

Difference -> ONE SECOND!

why!?

== EDIT ==

I use .NET Framework 4. VS2010. Win XP. I found this: if I use .NET 3.5 or lower the speed changes: 0.5 sec. An Half. If I compile in debug or release mode it doesn't change.

If I use the executable without the debugger is blazing fast.

So I change my question: is .NET 4 slower then .NET 3? Why the Release mode works differently compared to the stand alone version?

Many thanks.

The code ".Click += ..." is transformed into ".add_Click( ... )". The "add_Click" method can have some logic checks.

You can little-bit speed up with no recreation of delegate:

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

EDIT:

Are you sure, the bottleneck is the attaching the handlers? I tried the for loop (100 loops) with attaching the eventhandler to Click event and I get this results:

/* 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

The source code:

    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));
    }

EDIT 2: I tried compare time spent with attaching Click handler vs. attaching MouseUp handler. It does not seems, the attaching MouseUp event is faster than Click event.

I think the problem will be somewhere else. Don't GC collect during your loop? Or don't you do something else there?

Results:

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

Code:

    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));
    }

EDIT : The body of add_Click method (= Click += ...) is rough:

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

The MouseUp events will looks similar. At least both events using Events property for holding lists of delegates for events.

But if I tried several things I can not get the problems with the events as you wrote :(. Can you reproduce same behaviour on another computers?