【问题标题】:Winforms multithreading: Is creating a new delegate each time when invoking a method on the UI thread needed?Winforms多线程:每次调用UI线程上的方法时是否需要创建一个新委托?
【发布时间】:2011-05-16 02:00:22
【问题描述】:

我想调用一个方法来操作 UI 线程上的控件。我的代码有效,我想优化。我指的是这个resource on MSDN
根据那里,我们应该这样做

public delegate void myDelegate(int anInteger, string aString);
//...
Label1.Invoke(new myDelegate(myMethod), new Object[] {1, "This is the string"});

这会在每次调用时引入孤立的委托对象(内存泄漏)吗?

当我使用如下委托的静态实例执行此操作,然后在每次调用时使用此实例来调用时:

private static _delegateInstance = new myDelegate(myMethod);
//...
Label1.Invoke(_delegateInstance , new Object[] {1, "This is the string"});

这是线程安全的吗?因为委托实例只创建一次,所以我的性能会稍微好一点吗?

【问题讨论】:

    标签: c# winforms multithreading delegates invoke


    【解决方案1】:

    这会在每次调用时引入孤立的委托对象(内存泄漏)吗?

    不会的,没关系。

    但是为了避免每次创建委托,您可以使用一些existing(如果您的方法采用 2 个字符串参数并且没有返回):

    Label1.Invoke.Invoke((Action<string, string>)myMethod, 
        new object[] { 1, "This is the string" });
    

    【讨论】:

      【解决方案2】:

      首先,C# 是一种托管语言,因此没有内存泄漏。永远。

      第二,不要把MSDN当做优化的最终裁决。您在那里发现的许多代码 sn-ps 甚至不符合 MS 自己的编码标准(甚至是其中最基本的标准),甚至不符合常识。

      三、行:private _delegateInstance = new myDelegate(myMetho);不会产生任何静态的东西。它创建一个变量来保存从 new myDelegate(myMethod) 返回的新实例。

      最后,使用“new”关键字肯定会在每次调用中创建新的 myDelegate 对象,以及与您编写的第二个代码 sn-p 非常不同的行为,但在某些情况下这是必需的。

      您可能想使用您编写的第二个选项,但真正的事实是您应该花时间阅读\了解更多关于委托和 C# 的一般知识。

      祝你好运,尽情享受。

      【讨论】:

      • 你错了,C#/.net 中很有可能发生内存泄漏!
      • 我第二个贾斯特。它们会在应用程序退出时被清除,但在运行时很可能会一直分配不必要的对象。
      • 感谢您提到静态的东西。我更改了示例代码。
      【解决方案3】:

      上面的两个答案给出了一些见解。有一篇好文章here如果你想得到一些更深入的信息。

      这两种方法都是线程安全的,因为在调用时线程池会为每个调用分配一个线程。存在锁定的可能性,但如果您阅读了该文章,则有一些解决方法。

      此外,您需要记住,.Net 处理 UI 线程的方式略有不同。如果您正在处理 WPF,则必须考虑调度程序。见here

      最终,我不确定第二段代码是否会大幅提升性能,所以我倾向于坚持使用第一段。

      N.

      【讨论】:

      • 请记住,“以上”是相对的,并且随着时间的推移会发生变化! :-)
      【解决方案4】:

      另一种“模式”(如果可以这样调用的话)是让方法简单地调用自身,假设它是Form 类的一部分:

      void myMethod(int anInteger, string aString)
      {
          if (InvokeRequired)
          {
              Invoke(new Action<int,string>(myMethod),anInteger,aString);
              return;
          }
      
          Label1.Text = aString;
      }
      

      Action 对象将留在堆上,更改文本属性,然后在下一次扫描时被 GC。除非该方法保留一些外部资源,例如 IE 的句柄、文件等,否则我看不出它会影响性能。

      【讨论】:

      • 感谢您对垃圾收集发表评论。
      【解决方案5】:

      您的第一个 sn-p 每次都会创建一个委托对象实例。这不会导致任何泄漏,但会增加需要进行垃圾回收的对象数量。

      您的第二个 sn-p 不会每次都创建委托对象,但不可能(假设 myMethod 是实例方法),因为静态成员不能使用实例成员。

      Darin Dimitrov 是错误的 - 他的代码使用现有的 Action 委托而不是自定义委托,但它仍然每次都会创建一个 Action 委托对象(与您的第二个 sn-p 不同)。 因此,您可以使用以下代码:

      private Action<int, string> _delegateInstance = myMethod;
      //...
      Label1.Invoke(_delegateInstance , new Object[] {1, "This is the string"});
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-21
        • 1970-01-01
        相关资源
        最近更新 更多