2016-12-03 23 views
5

ı Görev nesneleri oluşturmak ki (ben kontrol etmediğini) iki bağımsız zaman uyumsuz işlevleri var diyelim:Bağımsız C# görevleri nasıl zincirlenir?

Task A(); 
Task B(); 

ve diğer bazı zaman uyumsuz olmayan fonksiyonunu tek bir inşa nasıl

void X(); 

Bunların tümünü sırayla yürüten ve daha fazla sürekliliğin (X'den sonra uygulanacak olan) eklenmesini sağlayan görev zinciri.

Eğer bunu yaparsam: B Yeni Görev zincirini başlayacak çünkü, çalışmıyor

Task Sequential() 
{ 
    return A() 
    .ContinueWith(t => { B(); }) 
    .ContinueWith(t => { X(); }); 
} 

. Eğer B'nin tamamlanması uzun zaman alırsa, önce X idam edilecektir (Sıralı Arayanın arayıcısı ne olursa olsun, İade Edilen Görev ile devam edebilir). B Görevini emsali olarak tek bir Görev zincirinde son öğe olmak için X'e ihtiyacım var.

Eğer bunu yaparsam:.

Arayan Sıralı() ContinueWith yaparsa halde A, B ve X şimdi, sırayla çalıştırır çünkü sadece kısmen, sorunu çözer
Task Sequential() 
{ 
    return A() 
    .ContinueWith(t => { B().ContinueWith(t => { X(); }); }); 
} 

, sürdürülmesinin B ve X'e paralel olarak yürütecektir, X.

+0

Alex'in cevabı gitmek isteyeyim yoludur. Ancak sizin amaçlarınız için, yapmaya çalıştığınız şey bir sözün kullanılmasını gerektirecektir ('TaskCompletionSource 'hizmet vermektedir). –

+1

'Task.WaitAll (A(), B()) .We (t => X())' 'a' ve 'B' bağımsız olduğunu söylerseniz, bir seçenek değil mi? – VMAtm

+0

@VMAtm, 'Task.WhenAll' demek istiyorsunuz. –

cevap

7

Kullanılmaması için herhangi bir sebep var mı? Örneğin,

async Task Sequential() 
{ 
    await A(); 
    await B(); 
    X(); 
} 
+0

Teşekkürler, işe yaradı! –

4

.NET Task girmesinden bu yana bu senaryo karşılamak üzere kullanılabilir bir şık küçük uzantısı yöntemi var, (eğer, şunları yapmalısınız eğer) diğer yanıtlar önerildiği şekilde async/await kullanamazsınız varsayarsak 4.0: System.Threading.Tasks.TaskExtensions.Unwrap. Bir (veya Task<Task<TResult>>) alır ve bitişik bir Task (veya sırasıyla Task<TResult>) içine "düzleştirir", bu da hem dış görevin hem de iç görevin tamamlanmasını temsil eder.

Task Sequential() 
{ 
    return A() 
     .ContinueWith(t => B()).Unwrap() 
     .ContinueWith(t => X()); // You said X() is "non-async", so no Unwrap here. 
} 

Elde edilen Task beklenen amacıyla, bütün görev ardışık zincirinin tamamlayıcıları: Verilerin yöntemi olarak yeniden olabilir uzatma yöntemi kullanarak

.

da aslen Görev Paralel Kütüphanesi ilk günlerinde bu çok amaç için icat the concept of "child tasks" vardır, ancak kullanımı korkunç şekilde zordur ve görevleri şunları yapabilirsiniz başladı şekli üzerinde büyük bir kontrole sahip olmasını gerektirir yok. Yine de, bilmeye değer (eğer sadece eğitim içindeyseniz).

2

Microsoft'un Reaktif Çerçevesi (NuGet "System.Reactive") kullanarak bunu yapmak için oldukça düzgün bir yol var.

public Task A() { return Task.Run(() => { "A".Dump(); Thread.Sleep(1000); "A".Dump(); }); } 
public Task B() { return Task.Run(() => { "B".Dump(); Thread.Sleep(1000); "B".Dump(); }); } 
public void X() { "X".Dump(); Thread.Sleep(1000); "X".Dump(); } 

Sonra Sequential().Wait(); çalışan bu üretir:

public Task Sequential() 
{ 
    return 
    (
     from a in Observable.FromAsync(() => A()) 
     from b in Observable.FromAsync(() => B()) 
     from c in Observable.Start(() => X()) 
     select c 
    ).ToTask(); 
} 

biz yöntemleri tanımlarsanız

bu vardır

 
A 
A 
B 
B 
X 
X 
İlgili konular