Görevle aynı tamamlanmış bir görevi bekleyin.


117

Şu anda Stephen Cleary'nin " C # Yemek Kitabında Eş Zamanlılık " ı okuyorum ve aşağıdaki tekniği fark ettim:

var completedTask = await Task.WhenAny(downloadTask, timeoutTask);  
if (completedTask == timeoutTask)  
  return null;  
return await downloadTask;  

downloadTaskbir çağrıdır httpclient.GetStringAsyncve timeoutTaskyürütülmektedir Task.Delay.

Zaman aşımına uğramaması durumunda downloadTask, zaten tamamlanmıştır. downloadTask.ResultGörev zaten tamamlanmışken neden geri dönmek yerine ikinci bir bekleme yapmak gerekiyor ?


3
Burada eksik bir bağlam var ve insanlar kitaba hemen erişemedikleri sürece, onu eklemeniz gerekecek. Nedir downloadTaskve timeoutTask? Onlar ne yapar?
Mike Perrenoud

7
Burada başarılı bir şekilde tamamlandığına dair gerçek bir kontrol görmüyorum. Görev çok iyi hatalı olabilir ve bu durumda davranış farklı olacaktır ( AggregateExceptionile Resultilk istisna ExceptionDispatchInfoile arasındaki fark await). Stephen Toub'un ".NET 4.5'te Görev İstisnası İşleme" bölümünde daha ayrıntılı olarak tartışıldı: blogs.msdn.com/b/pfxteam/archive/2011/09/28/… )
Kirill Shlenskiy

Bunun bir cevabı @KirillShlenskiy yapmalıdır
Carsten

@MichaelPerrenoud Haklısın, fark ettiğin için teşekkürler, soruyu düzenleyeceğim.
julio.g

Yanıtlar:


160

Burada zaten bazı iyi cevaplar / yorumlar var, ama sadece içeri girmek için ...

(Veya ) awaityerine tercih etmemin iki nedeni var . Birincisi, hata işlemenin farklı olmasıdır; istisnayı bir . İdeal olarak, eşzamansız kod , özellikle istemediği sürece hiçbir zaman uğraşmak zorunda kalmamalıdır .ResultWaitawaitAggregateExceptionAggregateException

İkinci neden biraz daha inceliklidir. Bloguma tarifine göre (ve kitapta), Result/ Waitkilitlenmeleri neden olabilir ve bir kullanıldıklarında bile daha ince kilitlenmeleri neden olabilir asyncyöntemle . Yani, kodu okurken bir Resultveya gördüğümde Wait, bu acil bir uyarı bayrağıdır. Result/ WaitSen eğer sadece doğru kesinlikle emin görev zaten tamamlanmış olduğunu. Bunu yalnızca bir bakışta görmek zor değil (gerçek dünya kodunda), aynı zamanda kod değişiklikleri için daha kırılgandır.

Yani demek değil Result/ Waitgerektiğini asla kullanılamaz. Bu yönergeleri kendi kodumda takip ediyorum:

  1. Bir uygulamadaki zaman uyumsuz kod yalnızca kullanabilir await.
  2. Eşzamansız yardımcı program kodu (bir kitaplıkta) , kod gerçekten onu gerektiriyorsa , bazen Result/ kullanabilir Wait. Böyle bir kullanım muhtemelen yorum içermelidir.
  3. Paralel görev kodu Resultve kullanabilir Wait.

(1) 'in açık ara ortak bir durum olduğuna dikkat edin, bu nedenle awaither yerde kullanma ve diğer durumları genel kuralın istisnaları olarak görme eğilimim .


Projelerimizde 'await' yerine 'result' kullanarak kilitlenme ile karşılaştık. karışık kısım derleme hatası yaşamıyor ve kodunuz bir süre sonra bozuluyor.
Ahmad Mousavi

@Stephen bana neden "İdeal olarak, eşzamansız kod özellikle istemediği sürece AggregateException ile hiçbir zaman uğraşmak zorunda
kalmamalıdır

4
@vcRobe Çünkü sarmalayıcıyı awaitengelliyor AggregateException. AggregateExceptioneşzamansız programlama için değil paralel programlama için tasarlanmıştır.
Stephen Cleary

2
> "Bekle, yalnızca görevin zaten tamamlandığından kesinlikle eminseniz doğrudur." .... O halde neden Bekle deniyor?
Ryan The Leach

4
@RyanTheLeach: Asıl amacı Dinamik Görev Paralellik örneklerine Waitkatılmaktı . Eşzamansız örnekleri beklemek için kullanmak tehlikelidir. Microsoft, yeni bir "Promise" türü sunmayı düşündü, ancak bunun yerine mevcut olanı kullanmayı seçti ; Eşzamansız görevler için mevcut türü yeniden kullanmanın değiş tokuşu, eşzamansız kodda kullanılmaması gereken birkaç API ile sonuçlanmanızdır. TaskTaskTaskTask
Stephen Cleary

12

Kitapta ne olduğuna inandığım timeoutTaskbir ürünü ise bu mantıklı Task.Delay.

Task.WhenAnydöndürür Task<Task>, burada iç görev, argüman olarak geçtiğiniz görevlerden biridir. Şu şekilde yeniden yazılabilir:

Task<Task> anyTask = Task.WhenAny(downloadTask, timeoutTask);
await anyTask;
if (anyTask.Result == timeoutTask)  
  return null;  
return downloadTask.Result; 

Her iki durumda da, downloadTaskzaten tamamlandığı için return await downloadTaskve arasında çok küçük bir fark vardır return downloadTask.Result. AggregateExceptionYorumlarda @KirillShlenskiy'nin belirttiği gibi , ikincisi, herhangi bir orijinal istisnayı tamamlayacak. İlki, orijinal istisnayı yeniden fırlatır.

Her iki durumda da, istisnaları nerede ele alırsanız AggregateExceptionalın, hatanın nedenine ulaşmak için yine de kontrol etmelisiniz .

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.