2010-11-26 59 views
5

我想调用一个在UI线程上操作控件的方法。我的代码有效,我想优化。我指的是这个resource on MSDN
据那里,我们应该做的Winforms multithreading:每次在UI线程上调用方法时都需要创建一个新的委托?

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

请问这是线程安全的?因为委托实例只创建一次,所以我认为它的性能略好一些?

回答

1

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

不,它不会,它是可以的。

但为了避免每次创建一个代表,你可以使用一些existing的(如果你的方法需要2个字符串参数并没有返回):

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

谢谢,这个技巧非常好! – Marcel 2010-11-26 10:37:16

0

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

其次,当您尝试优化时,不要将MSDN作为最终裁决。你发现的许多代码片段甚至都不符合MS自己的编码标准(甚至是最基本的编码标准)甚至常识。

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

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

您可能想要使用您编写的第二个选项,但真实的事实是您应该花时间阅读一些关于代表和C#的一般信息。

祝你好运,享受。

+4

你错了,在C#/ .net中内存泄漏非常有可能! – Jaster 2010-11-26 09:11:35

+0

我是第二个Jaster。他们会在应用程序退出时清理,但在运行时很可能会有不必要的对象被分配。 – Marcel 2010-11-26 09:28:03

+0

感谢提到静态的东西。我改变了示例代码。 – Marcel 2010-11-26 09:28:29

2

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

这两种方法都是线程安全的,因为在调用时线程池为每个调用分配一个线程。有锁定的可能性,但如果你阅读那篇文章,那么有办法。

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

最终,我不确定你会在第二段代码中获得巨大的性能提升,所以我会倾向于坚持第一段。

N.

2

一种替代“模式”(如果它可以被称为是)是使方法简单地调用自身,假设它是一个Form类的一部分:

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

    Label1.Text = aString; 
} 

Action对象将停留在堆上,更改文本属性,然后在下一次扫描时GC'd。我不能看到它是一个性能问题,除非该方法持有某些外部资源,例如IE,文件等的句柄。

0

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

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

Darin Dimitrov是错误的 - 他的代码使用现有的Action委托而不是自定义的委托,但它每次都会创建一个Action委托对象(与第二个片段不同)。 所以,你可以使用下面的代码:

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