2010-11-26 52 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"}); 
相關問題