2017-05-23 82 views
0

我是新來的所有.NET中的並行編程模式,我想知道兩件事情:等待並行編程來完成所有任務,而無需凍結了GUI

  1. 我怎麼能等待所有我的任務完成運行,而不會凍結我的主要形式。
  2. 我的方法是解決以下問題最好的方法去做呢?

我有一個private async Task RunTask(string task)方法,我需要運行多少次我的任務。

private async void button_click(object sender, EventArgs e)類中,我有一個名爲tasklist的字符串列表,它初始化我需要運行的任務。我運行下面的代碼:

Thread thread = new Thread(()=> Parallel.ForEach(tasklist, t => RunTask(t))); 
thread.Start(); 
RunOnCompletionOfTasks(); 

我需要能夠利用我所有的CPU核心和在儘可能短的時間最短運行所有任務。我想Parallel.ForEach是實現這一目標的最佳方式,但我的任務也是async,因爲它們具有需要等待其他方法的功能。我的任務還會在其執行期間向類中的List<string>對象追加一個字符串。

Parallel.ForEach導致我的Windows窗體凍結,所以我把它封裝在一個線程中。這個問題是RunOnComlpetionOfTasks();在我的任務完成之前運行。

什麼是最有效的方式讓我運行我所有的RunTask任務,然後在完成時運行RunOnCompletionOfTasks而不凍結Windows窗體?

請謝謝。

+0

我認爲您正在尋找'await Task.WhenAll' – BradleyDotNET

回答

3

如果您需要執行多個Tasks(這是可等待的),那麼Parallel.ForEach可能不是最佳選擇。它是真正爲CPU綁定的進程設計的,不支持async操作。

您可以嘗試使用Task.WhenAll()重寫代碼:

var tasks = tasklist.Select(RunTask); 
// assuming RunTask is declared as `async Task` 
await Task.WhenAll(tasks); 

這樣你都在利用你的方法調用中使用async/await格局。

相反,如果你意識到你的任務是不正確async(並且是唯一的CPU綁定),您可以嘗試執行Parallel.ForEach簡單Task

await Task.Run(() => Parallel.ForEach(tasklist, RunTask); 
// assuming RunTask is not `async Task` 
+0

謝謝。 'Task.WhenAll'似乎很有效率。然而,我仍然遇到了在任務運行時GUI凍結的問題。任何想法如何克服這一點? –

+0

你是否正在等待'private async void button_click'處理程序中的那些任務?如果是的話,你應該確保你的任務沒有做CPU工作。如果他們這樣做,他們不是有效運行異步,你應該依靠第二個選項。 –

+0

把整個功能放在你的答案中。例如,私人異步無效clickHandler.If你這樣做,然後它是他的問題的完美解決方案。 – rolls

0

首先內關閉所有你需要區分平行和異步:

  1. 當你需要做一些事情時,IO異步通常會播放。

  2. 當你需要做一些計算(如歸檔文件 或圖像處理)是平行的東西通常會發揮。

異步等待模式它只是一個快捷方式,而不是銀子彈。

如果您只需要平行計算,我建議使用像ParallelForEach這樣的TPL類似的並行工作人員,他們會玩酷和優化以獲得最佳性能。

如果你正在嘗試執行一些IO操作,這可能是有道理的,但在或多或少的巨大處理數據量 - 如服務器應用程序。

您的處理器不能做更多的話,就可以

任何並行工作人員窗臺不幫助你,如果你的任務是不是水貨。 請注意任何上下文切換都有一定的代價。 TaskSheduler將使用隊列來減少線程數量,但它會再次執行某些操作。

線程新線程是邪惡的(至少在這裏)。您的處理器將切換到一個更線程更頻繁(多個線程 - 多個交換機)

最後: 儘量不要使用喲TPL的事情,當你不知道如何做事情的工作。只需使用你需要的類,不要做不真正優化的優化。

PS 在UI中使用ContinueWith。 TPT中的任何東西都會返回具有此方法的任務, 更新UI請確保您當前正在使用的線程。