PrevTask.Wait () 'in ContinueWith ile (Görevler kitaplığından) kullanılması önerilir mi?


88

Bu nedenle, geçenlerde .ContinueWith for Tasks'ımı nasıl kullandığımın onları kullanmanın doğru yolu olmadığı söylendi. Henüz internette bunun kanıtını bulamadım, bu yüzden sizlere soracağım ve cevabın ne olduğunu göreceğim. İşte .ContinueWith'i nasıl kullandığımın bir örneği:

public Task DoSomething()
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 2");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 3");
    });
}

Şimdi bunun basit bir örnek olduğunu ve çok hızlı çalışacağını biliyorum, ancak her görevin biraz daha uzun işlem yaptığını varsayalım. Yani, bana söylendiğine göre .ContinueWith içinde prevTask.Wait () demeniz gerekir; aksi takdirde önceki görev bitmeden çalışabilirsiniz. Bu mümkün mü? İkinci ve üçüncü görevimin yalnızca önceki görevleri tamamlandığında çalışacağını varsaydım.

Bana kodu nasıl yazacağım söylendi:

public Task DoSomething()
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
    })
    .ContinueWith((prevTask) =>
    {
        prevTask.Wait();
        Console.WriteLine("Step 2");
    })
    .ContinueWith((prevTask) =>
    {
        prevTask.Wait();
        Console.WriteLine("Step 3");
    });
}

Yanıtlar:


115

Ehhh .... Bence mevcut cevaplardan bazılarında bir şey eksik: istisnalar olursa ne olur?

WaitBir devam ettirme talebinde bulunmanızın tek nedeni , devamın kendisindeki öncülden potansiyel bir istisna gözlemlemektir. Aynı gözlem Result, a durumunda erişirseniz Task<T>ve ayrıca manuel olarak erişirseniz de olur.Exception mülke . Açıkçası aramaz Waitveya erişmezdim Resultçünkü bir istisna varsa, gereksiz ek yük olan yeniden yükseltme bedelini ödersiniz. Bunun yerine, IsFaultedmülkü öncülden kontrol edebilirsiniz Task. Alternatif olarak, yalnızca TaskContinuationOptions.OnlyOnRanToCompletionve ile başarıya veya başarısızlığa dayalı olarak çalışan birden çok kardeş sürekliliği zincirleyerek çatallı iş akışları oluşturabilirsiniz TaskContinuationOptions.OnlyOnFaulted.

Şimdi, devamdaki öncül istisnasını gözlemlemek gerekli değildir, ancak "Adım 1" başarısız olursa, iş akışınızın ilerlemesini istemeyebilirsiniz. Bu durumda: belirterek TaskContinuationOptions.NotOnFaultedlistenizeContinueWith çağrılar şimdiye bile tetiklenmesini devamı mantığı engelleyecektir.

Unutmayın ki, kendi devamlarınız istisnayı gözlemlemezse, bu genel iş akışının tamamlanmasını bekleyen kişi onu gözlemleyecektir. Ya onlar konum Waitüzerinde ing Taskmemba veya tamamlandığında bilmek kendi devamına tacked var. İkincisi ise, devam etmelerinin yukarıda bahsedilen gözlem mantığını kullanması gerekecektir.


2
Sonunda biri doğru cevap veriyor. @ Travyguy9 Lütfen bunu @DrewMarsh cevabını okuyun ve hakkında daha fazlasını okuyunTaskContinuationOptions
Jasper

2
Harika yanıt, "Unutmayın ki, kendi devamlarınız istisnayı gözlemlemezse, bu genel iş akışının tamamlanmasını bekleyen kişi onu gözlemleyecek kişi olacaktır." Yine de bir soru, göreviniz beklenmediğinde, varsayılan garson kimdir? (Bunun cevabını bulamadık)
Thibault D.

20

Doğru kullanıyorsunuz.

Hedef Görev tamamlandığında eşzamansız olarak yürütülen bir devamlılık oluşturur .

Kaynak: Task.ContinueWith Method (Action as MSDN)

Aramak zorunda prevTask.Wait()herTask.ContinueWith çağrıda gereksiz mantığı tekrar etmenin tuhaf bir yolu gibi görünüyor - yani "çok daha emin" olmak için bir şeyler yapmak, çünkü aslında belirli bir kod parçasının ne yaptığını anlamıyorsunuz. ArgumentNullExceptionZaten fırlatılacağı bir yere atmak için bir boşluğu kontrol etmek gibi .

Öyleyse hayır, size bunun yanlış olduğunu söyleyen ve muhtemelen neden Task.ContinueWithvar olduğunu anlamıyor .


16

Bunu sana kim söyledi?

MSDN'den Alıntı :

Hedef Görev tamamlandığında eşzamansız olarak yürütülen bir devamlılık oluşturur.

Ayrıca, bir önceki görevin tamamlanmasını beklemeseydi , Devam Et'in amacı ne olurdu ?

Hatta kendiniz de test edebilirsiniz:

Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
        Thread.Sleep(2000);
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("I waited step 1 to be completed!");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 3");
    });

5

Gönderen MSDN tarihinde adlıTask.Continuewith

Döndürülen Görev, mevcut görev tamamlanana kadar yürütülmek üzere zamanlanmayacaktır. ContinuationOptions parametresiyle belirtilen kriterler karşılanmazsa, devam görevi zamanlanan yerine iptal edilir.

İlk örnekte çalışmasını beklediğiniz yolun doğru olduğunu düşünüyorum.


2

Task.Factory.StartNew yerine Task.Run kullanmayı da düşünebilirsiniz.

Stephen Cleary'nin blog yazısı ve Stephen Toub'un referans verdiği gönderi farklılıkları açıklıyor. Bu cevapta bir de tartışma var .


4
Asıl soruyu ele almadığı için olumsuz oy verildi. Biraz değer katar, ancak bir yorum olmalıdır.
Sinaesthetic

0

Erişerek Task.Result, aslında benzer bir mantık yürütürsünüz.task.wait


Evet. Wait () yönteminden kaçınabiliriz. Ama sonuç görevleri sadece, örneğin Görev <bool> ile çalışır
Alexander Ulmaskulov

Asıl soruyu ele almadığı için olumsuz oy verildi. Biraz değer katar, ancak bir yorum olmalıdır.
Sinaesthetic

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.