2011-04-28 36 views
5

我已經看遍了所有,我找不到答案。 是更好,更糟糕的,或漠不關心的使用方法:Control.Invoke與具有TaskScheduler的任務

{ 
... 
RefreshPaintDelegate PaintDelegate = new RefreshPaintDelegate(RefreshPaint); 
Control.Invoke(PaintDelegate); 
} 

protected void RefreshPaint() 
{ 
    this.Refresh(); 
} 

......或者......

Task.Factory.StartNew(() => 
{ 
    this.Refresh(); 
}, 
CancellationToken.None, 
TaskCreationOptions.None, 
uiScheduler); 

回答

3

假設uiScheduler是一個將調用委託給UI線程的調度程序,我會說在功能上,使用這兩者是無關緊要的(除了在調用完成之前對Control.Invoke的調用將阻塞,而對Task的調用不會,但是,您可以始終使用Control.BeginInvoke使它們在語義上相同)。

從語義的角度來看,我會說使用Control.Invoke(PaintDelegate)是一個更好的方法;當使用Task時,您正在做一個隱式聲明,指出您希望執行一個工作單元,並且通常該工作單元具有與其他工作單元一起安排的上下文,它是調度程序,用於確定如何委派該工作(通常,它是多線程的,但在這種情況下,它被編組到UI線程中)。還應該說,uiSchedulerControl之間沒有明確的聯繫,鏈接到UI線程,應該調用一個線程(通常,它們都是相同的,但可能有多個UI線程,儘管很稀少)。

但是,在使用Control.Invoke時,您想要執行的操作的意圖很明確,您希望將呼叫整理到Control正在抽取消息的UI線程,並且此調用完全表明。

但我認爲最好的選擇是使用SynchronizationContext實例;它抽象出您需要將呼叫同步到該上下文的事實,而不是其他兩個選項,這些選項對呼叫中的意圖(Task)或對於它的完成方式非常具體(Control.Invoke)不明確。

0

這是不一樣的。第一個版本將阻止調用線程,直到UI線程準備調用該方法。對於非阻塞版本,您應該使用Control.BeginInvoke,它也會立即返回。

除此之外(如果您將任務與線程池線程進行比較),使用它們幾乎沒有什麼區別。

[編輯]

在這種情況下,存在Task.Factory.StartNewControl.BeginInvoke(但不Invoke正如我上面寫)之間沒有差別,因爲只有一個單一的GUI線程可以執行代碼。無論您使用其中任何一個進行了多少次調用,它們仍將在UI線程變爲空閒時依次執行。

+0

但是['BeginInvoke'](http://msdn.microsoft.com/en-us/library/system.windows.forms.control.begininvoke.aspx)不會。與「Invoke」相同的語法,但它是異步的。 – 2011-04-28 12:07:48

+0

查看更多信息,請參閱[Invoke()和BeginInvoke()](http://stackoverflow.com/q/229554/616329)之間的區別。 – 2011-04-28 12:10:43

+0

所以Task.Factory.StartNew()會更加開放並行嗎?它會安排刷新發生,並允許調用線程繼續,對不對? – 2011-04-28 12:10:48