2012-11-26 39 views
5

我想連鎖Task s,然後並行啓動鏈。 這個片段只是爲了說明我的問題:適當的方式來連鎖任務

 var taskOrig = new Task(() => { }); 
     var task = taskOrig; 
     foreach (var msg in messages) 
     { 
      task=task.ContinueWith(t => Console.WriteLine(msg)); 
     } 
     taskOrig.Start(); 

一切正常,只是有點完美主義裏我不喜歡有空方法執行第一() => { }

有什麼辦法避免呢?

我明白它幾乎不影響性能(除非你經常這樣做),但仍然如此。在我的情況下,性能很重要,因此檢查每個迭代中是否存在任務不是實現它的方法。要做到這一點

+1

「在我的情況下的性能問題,所以檢查是否存在任務在每次迭代中不做到這一點的方式「:與實際執行任務相比,所需時間可以忽略不計。除非您確實衡量了性能影響,否則顯然是過早優化的情況。 –

+0

@ThomasLevesque你可能是對的,我只是想,也許我錯過了'任務'創建API中的東西。我將有機會衡量後來的表現。 – Anri

+0

你可能會發現TPL DataFlow很有趣 – sll

回答

3

你可以這樣做:

Task task = Task.FromResult<object>(null); 
foreach (var msg in messages) 
{ 
    task = task.ContinueWith(t => Console.WriteLine(msg)); 
} 

以前的解決方案將無法在4.0中工作。在4.0你需要做的,而不是以下幾點:(您可以在foreach循環之前,如果你喜歡移動SetResult到)

var tcs = new TaskCompletionSource<object>(); 
Task task = tcs.Task; 
foreach (var msg in messages) 
{ 
    task = task.ContinueWith(t => Console.WriteLine(msg)); 
} 

tcs.SetResult(null); 

從技術上講這是不一樣的延續將開始執行,而你還在增加更多。但這不太可能是個問題。

另一種選擇是使用這樣的:

public static Task ForEachAsync<T>(IEnumerable<T> items, Action<T> action) 
{ 
    return Task.Factory.StartNew(() => 
    { 
     foreach (T item in items) 
     { 
      action(item); 
     } 
    }); 
} 

一個例子用法是:

ForEachAsync(messages, msg => Console.WriteLine(msg)); 
+0

有一點需要注意:在.NET 4.0中,'Task.FromResult()'是新的.Net 4.0中,您需要使用TaskCompletionSource手動執行此操作。 – svick

+0

@svick正確的解決方案。 – Servy

+0

不錯,thanx,'Task.FromResult (null)' - 這正是我在Task Parallel lib中錯過的 – Anri

2

的一種方式,是在循環創建任務,如果它是空的,但你所提供的代碼看起來更好,對我來說:

Task task = null; 
foreach (var msg in messages) 
{ 
    if (task == null) 
     task = new Task(() => Console.WriteLine(msg)) 
    else 
     task = task.ContinueWith(t => Console.WriteLine(msg)); 
} 
task.Start(); 
+0

技術上 - 是的,但這意味着我將不得不在每一個循環中檢查它,所以它會變得更慢。性能很重要,我應該加上這個問題 – Anri

+0

你提供的代碼是非常好的,但我們等待其他選項 –

1

也許這樣的:

if(messages.Length > 0) 
{ 
    Task task = new Task(t => Console.WriteLine(messages[0])); 

    for(int i = 1; i < messages.Length; i++) 
    { 
     task = task.ContinueWith(t => Console.WriteLine(messages[i])); 
    } 
    task.Start(); 
} 
+0

這是最有效的選項,但它的可讀性較差... –

+0

謝謝,這是一個選項,但不會總是工作。有時你擁有的只是枚舉器,任務也可以通過其他方式添加 – Anri

+0

@Anri你也可以用枚舉器做同樣的事情(通過手動訪問它的'MoveNext()'和'Current'),除了它會更多代碼甚至更混亂。 – svick