我遇到了性能问题。我创建了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会变慢吗?或者我做错了什么?还是有最好的做法?
我正在使用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);
Button_Click和Button_Click是:
private void Button_Click(object sender, EventArgs e)
{
}
private void Button_ClickUP(object sender, MouseEventArgs e)
{
}
我将此代码放在一个按钮中,“Log”功能将结果显示在备忘录中。当我启用“Click”时,结果为01.05秒,但是当我启用“MouseUp”时,结果为00.00。
差异 - &gt;一秒钟!
为什么!?
==编辑==
我使用的是.NET Framework 4. VS2010。赢得XP。我发现了这个:如果我使用.NET 3.5或更低的速度变化:0.5秒。一半。 如果我在调试或发布模式下编译它不会改变。
如果我在没有调试器的情况下使用可执行文件的速度非常快。
所以我改变了我的问题:.NET 4比.NET 3慢吗?与独立版本相比,为什么发布模式的工作方式不同?
非常感谢。
答案 0 :(得分:5)
代码“.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
属性来保存事件的委托列表。
但是,如果我尝试了几件事,我就无法解决你写的事件的问题:(。 你能在另一台计算机上重现相同的行为吗?
答案 1 :(得分:4)
System.EventHandler
是委托类型,因此不会执行任何操作。这不能成为表现差异的根源
在内部添加新的Click
处理程序和新的MouseUp
事件处理程序是相同的。两者都致电Events.AddHandler
在我看来,唯一的区别可能是,Click
已经附加了其他事件处理程序而MouseUp
没有或反过来。
要检查我的假设是否正确,您可以复制并粘贴两个代码片段并执行两次,并测量第一次和第二次的持续时间。
如果Click
的两次运行都很慢而且MouseUp
的第二次运行速度很慢,则问题是,已存在Click
个处理程序并且已经存在一个处理程序比不存在时慢一个。
如果Click
的第一次运行速度很慢而第二次运行很快且MouseUp
的两次运行都很快,则问题是,没有现有的Click
处理程序并且添加已存在的处理程序更快比不存在时添加一个
我的回答是假设OP的观察结果是无副作用的。我实际上并没有测试他的结果是否可重复或合理。我的回答只是想证明Click
事件或System.EventHandler
确实没什么特别的。
答案 2 :(得分:0)
我试过了: -
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");
}
}
显示所有按钮并且事件似乎正确触发,事件处理程序分配太快而无法合理地测量。我的机器上不到一秒钟。
也许问题出在其他地方?
答案 3 :(得分:0)
尝试关闭IntelliTrace。有完全相同的症状。不在Visual Studio下运行时速度极快,但每个btn总是增加30ms。如果在Visual Studio下运行,则点击+ = i。
所以很可能IntelliTrace以某种方式挂钩到Click事件以进行详细的调试。