2012-11-26 31 views
5

Task s zincirini zincirlemek istiyorum, ardından zinciri paralel olarak başlatın. Beni boş yöntem () => { } ilk devir yapmış sevmez içZincir için uygun yol Görevler

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

Her şey biraz mükemmeliyetçi dışında çalışıyor: Bu parçacık sadece sorumu göstermektir.

Bundan kaçınmanın bir yolu var mı?

Anladığım kadarıyla Performansı zorlukla etkiliyor (gerçekten sık sık yapmadığınız sürece), ama yine de. Benim durumumdaki performans önemlidir, bu yüzden her yinelemede görev var olup olmadığını kontrol etmek bunu yapmanın yolu değildir. Bunu yapmanın

+1

"Performans hususlar: Bir örnek kullanım olacağını

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

:

Diğer bir seçenek böyle bir şey kullanmak olacaktır Bunu yapmanın yolu. ": Görev süresinin gerçekte yürütülmesiyle kıyaslandığında göz ardı edilebilir. Bir performans isabetini gerçekten ölçmediyseniz, bu kesinlikle bir erken optimizasyon olgusudur. –

+0

@ThomasLevesque muhtemelen haklısınız, belki de 'Görev' API oluşturma bir şey özledim düşündüm. Performansı daha sonra ölçmek için bir şansım olacak. – Anri

+0

TPL DataFlow'ı ilginç bir şekilde bulabilirsiniz – sll

cevap

3

Yapabilirsin Bunu yapın:

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

Önceki çözüm 4.0'da çalışmaz. In 4.0 yerine aşağıdakileri yapmanız gerekir: (. İsterseniz foreach döngüsünde önce hiç SetResult taşıyabilirsiniz)

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

tcs.SetResult(null); 

continuations süre yürütme başlayacak şekilde

Teknik olarak aynı değil Hala daha fazlasını ekliyorsun. Yine de bir sorun olmak pek olası değil. Her yineleme değil görev varsa o kadar kontrol benim durumumda

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

Bir not: 'Task.FromResult()' .Net 4.5, in .Net 4.0'da yenidir, bunu 'TaskCompletionSource' kullanarak el ile yapmanız gerekir. – svick

+0

@svick Right, çözüm eklendi. – Servy

+0

Nice, thanx, 'Task.FromResult (null)' - Görev Paralel lib'de tam olarak özlediğim şey budur – Anri

2

bir yolu, boş ise döngü içinde görev oluşturmak için, ancak sağlamak kod benim için daha iyi görünüyor:

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

Teknik olarak - evet, ama her döngüde kontrol etmek zorunda kalacağım, bu yüzden daha yavaş olacak. Performans önemlidir, sağladığınız soruya – Anri

+0

kodunu eklemeliyim, gerçekten güzel ama diğer seçenekleri bekleyelim –

1

Belki de bu:

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

En verimli seçenek bu, ama daha az okunabilir ... –

+0

Teşekkürler, bu bir seçenek, ama her zaman işe yaramayacak. Bazen sahip olduğunuz tüm numaralar sayıcıdır ve görevler başka yollarla da eklenebilir – Anri

+0

@Anri Aynısını senetleyici ile de yapabilirsiniz ("MoveNext()" ve "Current") el ile girerek, daha da fazlası olacaktır. kod ve daha da dağınık. – svick

İlgili konular