事件处理程序性能

2024-01-05

我有性能问题。我创建了 100 个新按钮,并且想要分配一个单击事件处理程序。我执行这段代码大约 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。

EDIT:

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

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

我将此代码放入按钮中,“日志”功能在备忘录中显示结果。当我启用“Click”时,结果是 01.05 秒,但当我启用“MouseUp”时,结果是 00.00。

差异 -> 一秒钟!

why!?

==编辑==

我使用.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;
}

EDIT:

您确定瓶颈是附加处理程序吗? 我尝试使用 for 循环(100 次循环)将事件处理程序附加到 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));
    }

EDIT 2:我尝试比较附加 Click 处理程序与附加 MouseUp 处理程序所花费的时间。似乎并非如此,附加的 MouseUp 事件比 Click 事件更快。

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

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 :的身体add_Click方法(=Click += ...)是粗糙的:

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

事件处理程序性能 的相关文章

  • 命名管道客户端无法连接到作为网络服务运行的服务器

    我有一个服务在网络服务帐户下运行 该服务只是设置一个命名管道并侦听连接 NamedPipeServerStream listeningPipe new NamedPipeServerStream ourservicepipe PipeDir
  • 更改图像颜色与透明背景

    我需要使用 c System Drawings 将透明背景上带有绿色圆圈的图像加载到位图图像中 这是最简单的部分 但是 我需要在将其添加到更大的图像之前更改圆圈的颜色 而不影响周围的透明度 就我而言 我需要将圆圈颜色更改为黄色并将其添加为太
  • 等待运算符错误

    我的代码有问题 我怎么解决这个问题 这个问题出现在await操作符中 public MyModel HttpClient client new HttpClient HttpResponseMessage response await cl
  • 提取单花括号内的值

    我想要一个收藏 value 一个字符串使用正则表达式 例如 lorem ipsum field1 lorem ipsum field2 lorem ipsum field1 lorem ipsum field2 field3 我会得到 fi
  • .NET 中的 Class.forName() 等效项?

    动态获取对象类型然后创建它的新实例的 C 方法是什么 例如 如何在 C 中实现以下 Java 代码的结果 MyClass x MyClass Class forName classes MyChildClass newInstance Lo
  • 析构函数与成员函数竞赛

    当我在析构函数内时 其他线程是否可能开始执行对象的成员函数 遇到这种情况该如何处理呢 C 没有内在的保护来防止在删除对象后使用它 忘记竞争条件 另一个线程可以在完全删除你的对象后使用你的对象 Either 确保只有一个位置 代码拥有该对象
  • 如何生成可变参数包?

    给定不相关的输入是否可以生成非类型参数包 我的意思是 我想改变这一点 template
  • 用 OpenCL C 编写快速线性系统求解器

    我正在编写一个 OpenCL 内核 它将涉及求解线性系统 目前我的内核太慢了 提高线性系统部分的性能似乎是一个不错的起点 我还应该注意 我并没有尝试使我的线性求解器并行 我正在研究的问题在宏观层面上已经是令人尴尬的并行 以下是我编写的 C
  • 优化正则表达式以过滤数千个 HTML 选择选项

    背景 我开发了一个基于 jQuery 的穿梭小部件 https stackoverflow com a 13557000 59087对于 HTMLselect元素 因为我找不到一个经过最低限度编码并提供正则表达式过滤器来补偿的元素变音符号
  • 使用信号和槽更新指针

    我对 Qt 很陌生 请帮我解决这个问题 我正在使用线程在后台执行密集操作 同时我想更新 UI 所以我使用 SIGNALS 和 SLOTS 为了更新 UI 我发出一个信号并更新 UI 让我们考虑下面的示例代码 struct sample QS
  • ef core 在更新数据库期间不使用 ASPNETCORE_ENVIRONMENT

    我使用 Visual Studio 通过一定的迁移来更新我的所有环境 使用下面的命令效果很好 update database Migration initMigrationProduct c ProductContext Environme
  • 如何在 C 语言中获取输入中的空格

    我想从控制台获取字符数组 它还包含空格 我在 C 中知道的唯一方法是 scanf 但是一旦遇到空格 它就会停止接受输入 我该做什么 这就是我正在做的事情 char address 100 scanf s address 尝试使用 fgets
  • “DeploymentItem”属性是什么意思?

    假设我们有一个简短的程序 namespace ConsoleTryIt static class Program static void Main string args var sum Add 1 2 private static int
  • 如何将 Boost Spirit 自动规则与 AST 结合使用?

    编辑 当我想在另一个规则上使用它时 我扩展了 sehe 的示例以显示问题 http liveworkspace org code 22lxL7 http liveworkspace org code 22lxL7 17 我正在尝试提高 Bo
  • 当一对迭代器初始化时,向量是否知道先保留?

    考虑以下代码 struct MyData MyData const BYTE pData size t uSize bucket pData pData uSize std vector
  • 快速将文本附加到文本框

    我有一个BackgroundWorker正在发布消息的线程 使用BeginInvoke在 GUI 中的文本框中 方法 write debug text 在文本框中显示文本使用AppendText并将文本写入Console 外观上是这样的Ba
  • 使用 DataGridViewCheckboxCell 真正禁用 DataGridView 中的复选框

    有谁知道如何使用 DataGridViewCheckboxCell 禁用 DataGridView 中的复选框 我可以将其设置为只读 并设置背景颜色 但我无法让复选框本身显示为禁用状态 有什么想法吗 Guess 你必须自己画 http so
  • C++ 在预处理器 #if 中对 sizeof() 比较抛出编译错误

    我有这个 它不会从 Visual Studio 编译错误 致命错误 C1017 无效的整数常量表达式 我该怎么做 template
  • 从数据库配置中的连接字符串中删除 SSIS 密码

    我有一个 SSIS 包 它使用 SQL 服务器中的 SSIS 配置表来检索 OLE DB 连接管理器的连接字符串属性 问题是我还需要相同的连接字符串来调用使用实体框架的程序集 我尝试访问连接管理器连接字符串属性 但 SSIS 总是删除密码
  • Java中精确的时间测量

    Java 提供了两种获取当前时间的方法 System nanoTime and System currentTimeMillis 第一个给出的结果以纳秒为单位 但实际精度比这要差得多 许多微秒 JVM 是否已经为每台特定机器提供了最佳的价值

随机推荐

  • 是时候通过 9600 波特串行发送 32KB 了?

    我想知道我的数学是否正确 如果我的波特率为 9600 那么这意味着每秒发送 9600 位 对吧 如果是这样 那么 9600 bit sec lt gt 1000 ms 9600 bit 0 1042 ms bit 因此 发送 32KB 应该
  • Cocoa Touch 中的协调控制器设计模式

    我正在创建一个带有大量自定义视图的 iOS 应用程序 因此 使用默认的 Cocoa 视图不是一个选项 然后 我决定和协调 中介控制器设计模式 在 Apress Pro Objective C Design Patterns for iOS
  • 主动配置

    Visual Studio 项目中的确切位置是活动配置 release debug等 存储 我相当确定它存储在 suo 文件中 它是一个二进制文件 存储各种用户 计算机特定设置 您可以找到有关此文件的更多信息here http msdn m
  • Git 哈希对象在 Powershell、CMD 和 Bash 中产生不同的 SHA1?

    我认为无论平台如何 SHA1 值都是相同的 我今天遇到了这个问题 希望我能在这里得到一些澄清 我的测试字符串是 Apple Pie In Bash echo Apple Pie git hash object stdin 23991897e
  • IP分片与重组

    我目前正在浏览我的网络幻灯片 想知道是否有人可以帮助我了解碎片和重组的概念 我了解它是如何工作的 即数据报如何被分割成更小的块 因为网络链接有一个 MTU 然而图片中的例子让我感到困惑 因此 前两部分显示的长度为 1500 因为这是 MSU
  • Promise 解析为子流 stdout 并拒绝子流 stderr

    我想建立一个使用以下命令生成子进程的承诺require child process spawn 该过程将其输出流式传输到stdout及其错误stderr 我希望承诺 reject child stderr stream or its dat
  • 如何通过特定选择来组织 Backbone 集合?

    我有一系列物品 我想跟踪当前的选择 当用户单击集合中的不同项目时 我想指示该项目已被选中并显示所选项目的详细信息 将此视为具有详细视图的列表 就像典型的电子邮件客户端 Example of a master detail layout so
  • 除了提交表单之外,在失去焦点时触发 html5 电子邮件验证器

    我有一个电子邮件输入字段 我使用 ajax 检查电子邮件是否已存在于我的数据库中 以防止该电子邮件输入失去焦点 我想在进行 ajax 调用之前确保输入的电子邮件格式正确 我可以使用 html5 内置电子邮件验证器来执行此操作还是必须编写自己
  • 如何引用使用无服务器框架创建的 AWS lambda 函数的 Arn 和名称

    我正在使用 Serverless Framework 创建 lambda 函数 并希望能够在 serverless yml 的其他部分交叉引用其 Arn 和名称 我很惊讶我发现这个有多困难 因为如果 lambda 是通过普通的 CloudF
  • VSCode 无法识别较新的 CSS

    VSCode 会在它无法识别的 CSS 下生成一条波浪线 例如 justify self start 无法识别命名网格线 这 col 给它带来问题 例如 grid template columns repeat 6 col 150px 我尝
  • CMD For 循环不保存 set /a 值

    不知道如何很好地解释这一点 所以这是代码 echo off set test 0 for f a in textfile txt do rem loops five times 5 lines in textfile txt set a t
  • 发送电子邮件时更改文本(字符串)的颜色

    当我将文本 字符串 输出到电子邮件时 我试图更改它的颜色 我的代码是 String appdata txtFromSpinner location getText date getText start getText finish getT
  • 在 TOpenDialog 中右键单击文件时,使用自定义样式会显示无效字符

    请参阅以下步骤进行重现 在 XE2 中运行良好 但在 XE8 中运行不佳 创建新的 VCL 表单应用程序 Delphi Place a TButton and a TOpenDialog在表格上 在按钮中OnClick事件调用OpenDia
  • Matlab中值滤波器代码

    我需要在 MATLAB 中对图像实现中值滤波 然而 我是不允许使用medfilt2 or ordfilt2MATLAB 中的函数 我们最近也开始学习MATLAB 是否有任何代码可用于中值滤波器或高斯滤波器 NB 这假设已安装图像处理工具箱
  • 如何将 Comet 与 Spring MVC 一起使用?

    我想添加一些彗星 服务器推送 http en wikipedia org wiki Comet programming 简单 Web 应用程序的功能 我无法找到有关如何执行此操作的最新信息 任何人都可以向我指出一些示例 教程 博客或任何最近
  • Android ACR122U NFC 集成

    See NFC 读取器 SELECT 通过 AID APDU 未路由到 Android 设备 https stackoverflow com q 50316799 2425802关于调试和最终结果 TL DR 读者可能已经不复存在了 我的
  • 验证 Knuth 洗牌算法尽可能无偏

    我正在实施一个高德纳洗牌 http en wikipedia org wiki Fisher E2 80 93Yates shuffle对于我正在从事的 C 项目 我试图从我的洗牌中获得最公正的结果 而且我不是 伪 随机数生成方面的专家 我
  • 创建一个 firemonkey 组件

    我正在 Delphi XE4 中使用 Firemonkey 但无法使用菜单项 Component gt New Component 创建新组件 无论该组件是 VCL 还是 Firemonkey 组件 或者我是否先创建一个包 结果都是相同的
  • 如何从命令行执行 SOAP wsdl Web 服务调用

    我需要进行 SOAP Web 服务调用https sandbox mediamind com Eyeblaster MediaMind API V2 AuthenticationService svc wsdl https sandbox
  • 事件处理程序性能

    我有性能问题 我创建了 100 个新按钮 并且想要分配一个单击事件处理程序 我执行这段代码大约 100 次 Buttons i Button Click new System EventHandler Button Click 大约需要2秒