2012-11-26 10 views
5

Taskを連鎖して、連鎖を開始します。私は空のメソッドが() => { }最初に実行した好きではないの内側に連鎖する適切な方法

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

すべてが少し完璧主義者を除いて正常に動作します: このコードは、ちょうど私の質問を説明することです。

これを避ける方法はありますか?

私は理解していますそれはパフォーマンスにほとんど影響を与えません(あなたが本当に頻繁にしない限り)。私の場合はパフォーマンスが重要なので、すべての反復でタスクが存在するかどうかを確認することはそれを行う方法ではありません。

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(); 
+1

「パフォーマンス事項:使用例は次のようになり

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

別のオプションは、このようなものを使用することですそれを行う方法」:実際にタスクを実行するのに比べると、無視できる時間です。パフォーマンスヒットを実際に測定していない限り、明らかに早すぎる最適化のケースです。 –

+0

@ThomasLevesqueあなたはおそらく正しいでしょう。私はたぶん私がタスクを作ってAPIを作っていないかもしれないと思った。後でパフォーマンスを測定する機会があります。 – Anri

+0

TPL DataFlowの興味深いのは – sll

答えて

3

あなたは可能性があり、それがnullの場合はループ内でタスクを作成することですが、あなたが提供するコードは私のために良く見える、それを行うための

+0

注: 'Task.FromResult()'は.Net 4.5の.Net 4.0で新しく、これは 'TaskCompletionSource'を使って手動で行う必要があります。 – svick

+0

@スウィック右、解決策が追加されました。 – Servy

+0

Nice、thanx、 'Task.FromResult (null)' - これはまさに私がTask Parallelのlibで逃したものです – Anri

2

一つの方法これを行う:

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

を継続しばらくの実行を開始しますよう技術的には同じではありませんあなたはまだ追加しています。しかしそれは問題になることはまずありません。そのタスクは反復ごとに存在するかどうかをチェックすることはありませんが、私の場合は

ForEachAsync(messages, msg => Console.WriteLine(msg)); 
+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