代码之家  ›  专栏  ›  技术社区  ›  Marcel

Winforms多线程:每次在需要的UI线程上调用方法时是否创建新的委托?

  •  5
  • Marcel  · 技术社区  · 14 年前

    我想调用一个在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"});
    

    这是线程安全的吗?我真的认为这有更好的性能,因为委托实例只创建一次?

    5 回复  |  直到 14 年前
        1
  •  1
  •   Darin Dimitrov    14 年前

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

    不,不会的,没事的。

    但是为了避免每次都创建委托,您可以使用 existing (如果您的方法接受2个字符串参数,但尚未返回):

    Label1.Invoke.Invoke((Action<string, string>)myMethod, 
        new object[] { 1, "This is the string" });
    
        2
  •  2
  •   Nick    14 年前

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

    这两个方法都是线程安全的,因为在调用时,线程池为每个调用分配一个线程。有可能会被锁定,但如果你读了那篇文章,你可以找到办法来解决这个问题。

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

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

    N。

        3
  •  2
  •   Chris S    14 年前

    另一种“模式”(如果可以调用它的话)是让方法简单地调用自己,假设它是 Form 班级:

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

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

        4
  •  0
  •   Neowizard    14 年前

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

    第二,当你试图优化时,不要把MSDN作为最终的规则。许多代码片段甚至都无法达到MS自己的编码标准(甚至是最基本的编码标准)甚至常识。

    第三,行:private _delegateInstance=new myDelegate(mymeto);不创建任何静态的。它创建一个变量,保存从新myDelegate(myMethod)返回的新实例。

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

    您可能想使用您编写的第二个选项,但实际情况是,您应该花点时间阅读并进一步了解委托和一般的C。

    祝你好运,快乐。

        5
  •  0
  •   Ark-kun    12 年前

    第一个代码段每次都创建一个委托对象实例。这不会导致任何泄漏,但会增加需要垃圾收集的对象的数量。

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

    Darin Dimitrov是错误的——他的代码使用了现有的动作委托而不是定制的委托,但是它每次都创建一个动作委托对象(不像你的第二个片段)。 因此,您可以使用以下代码:

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