Task.Result .GetAwaiter.GetResult () ile aynı mı?


328

Son zamanlarda çok sayıda asenkron yöntem kullanan bazı kodları okuyordum, ancak bazen bunları eşzamanlı olarak yürütmesi gerekiyor. Kod:

Foo foo = GetFooAsync(...).GetAwaiter().GetResult();

Bu aynı mı?

Foo foo = GetFooAsync(...).Result;

8
Ait Dokümanlar GetResult: "Bu tip ve üyelerinin derleyici tarafından kullanılmak üzere tasarlanmıştır." Diğer kişi kullanmamalıdır.
harcayan

32
Bu "zaman uyumsuz üzerinde senkronizasyon" olarak adlandırılır ve Görev nasıl uygulandığını bilmedikçe bir olabilir gerçekten kötü bir fikir. Birçok durumda anında kilitlenebilir ( örneğin asyncawait
MVC'de


14
Gerçek dünyada kurucularımız var, uygulamamız gereken "beklemediğimiz" arayüzlerimiz var ve her yere asenkron yöntemler veriliyor. Neden "tehlikeli", "kullanılmaması" veya "her ne pahasına olursa olsun kaçınılması" nı merak etmek zorunda kalmadan çalışan bir şey kullanmaktan memnuniyet duyarım. Async ile uğraşmak zorunda kaldığım her seferinde başım ağrıyor.
Larry

Yanıtlar:


173

Neredeyse. Yine de küçük bir fark: Taskbaşarısız olursa, GetResult()doğrudan neden olunan istisnayı Task.Resultatar, bir de AggregateException. Ancak, bunlardan herhangi birini kullanmanın anlamı asyncnedir? 100x daha iyi seçenek kullanmaktır await.

Ayrıca, kullanmak istemiyorsunuz GetResult(). Sadece derleyici kullanımı içindir, sizin için değil. Ama can sıkıcı istemiyorsanız AggregateException, kullanın.


27
@JayBazuzi Birim test çerçeveniz, çoğu çerçevenin en yeni sürümlerinin yaptığını düşündüğüm zaman uyumsuz birim testlerini destekliyorsa değil.
svick

15
@JayBazuzi: MSTest, xUnit ve NUnit'in tümü async Taskbirim testlerini destekliyor ve bir süredir var.
Stephen Cleary

18
100x'i geri itmek - eski kodu adapte ediyorsanız ve beklemek için yeniden yazmak gerekiyorsa kullanmak 1000x daha kötü.
takıldı

13
@AlexZhukovskiy: Kabul etmiyorum .
Stephen Cleary

15
The 100x better option is to use await.Bunun gibi ifadelerden nefret ediyorum, eğer awaitönünde tokat yapabilseydim yapardım. Ancak, Xamarin'de bana çok sık ne olduğu gibi zaman uyumsuz kodlara karşı çalışmak için zaman uyumsuz kod almaya çalıştığımda ContinueWith, kullanıcı arayüzünü kilitlememek için çok şey gibi şeyler kullanmak zorunda kalıyorum . Düzenleme: Bu eski olduğunu biliyorum, ama bu sadece kullanamayacağınız durumlar için hiçbir alternatif ile bu bildiren cevaplar bulmak benim hayal kırıklığı hafifletmez await.
Thomas

147

Task.GetAwaiter().GetResult()tercih edilir Task.Waitve Task.Resultistisnaları bir AggregateException. Ancak, her üç yöntem de kilitlenme ve iş parçacığı havuzu açlık sorunları için potansiyele neden olur. Hepsinin lehine kaçınılmalıdır async/await.

Aşağıdaki alıntı açıklıyor Task.Waitve Task.Resultbasitçe bir istisna yayılma davranışını içermeyen Task.GetAwaiter().GetResult()(nedeniyle "çok yüksek uyumluluk çubuğu").

Daha önce de belirttiğim gibi, çok yüksek bir uyumluluk çubuğumuz var ve bu nedenle değişiklikleri kırmaktan kaçındık. Bu nedenle, Task.Waither zaman sarma orijinal davranışını korur. Ancak, çalıştığınız eşzamanlı engellemeye benzer davranışlar istediğiniz Task.Wait, ancak orijinal istisnanın, bir AggregateException. Bunu başarmak için, Görev bekleyicisini doğrudan hedefleyebilirsiniz. “ await task;” Yazdığınızda , derleyici bunu Task.GetAwaiter()yöntemin kullanımına dönüştürür ve yöntemi olan bir örneği döndürür GetResult(). Hatalı bir Görevde kullanıldığında GetResult()orijinal istisnayı yayar (“ await task;” davranışını bu şekilde alır). Böylece “task.GetAwaiter().GetResult()“Bu yayılma mantığını doğrudan çağırmak istiyorsanız.

https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/

GetResult” Aslında “görevi hatalara karşı kontrol et” anlamına gelir

Genel olarak, eşzamansız bir görevde senkronize engellemeyi önlemek için elimden geleni yapıyorum. Ancak, bu kılavuzu ihlal ettiğim birkaç durum var. Bu nadir durumlarda, tercih ettiğim yöntem, GetAwaiter().GetResult()görev istisnalarını bir AggregateException.

http://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html


3
Yani temelde Task.GetAwaiter().GetResult()eşittir await task. İlk seçenek yöntem async(örneğin yapıcı) ile işaretlenemediğinde kullanılır varsayalım . Bu doğru mu? Eğer evet ise, o zaman en iyi cevapla çarpışır @ It'sNotALie
OlegI

5
@OlegI: Task.GetAwaiter().GetResult()daha eşdeğerdir Task.Waitve Task.Result(her üç eşzamanlı engellemek ve kilitlenmeleri için potansiyele sahip olacağını), ancak Task.GetAwaiter().GetResult()bekliyoruz görevin istisna yayılma davranışı vardır.
Nitin Agarwal

(Görev) .ConfigureAwait (false) .GetAwaiter (). GetResult (); ile bu senaryoda kilitlenmeleri önleyemezsiniz. ?
Daniel Lorenz

3
@DanielLorenz: Şu alıntıya bakın: "Kilitlenmeleri önlemek için ConfigureAwait (false) kullanmak tehlikeli bir uygulamadır. - ve ikinci taraf kodu. Kilitlenmeyi önlemek için ConfigureAwait'i (false) kullanmak en iyi ihtimalle sadece bir hack'tir. ... daha iyi çözüm “Zaman uyumsuz kodda engelleme” dir. - blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Nitin Agarwal

4
Anlamıyorum. Görev Bekle ve Görev.Tasarım tasarım tarafından kırıldı mı? Neden eskimiş değiller?
osexpert

69

https://github.com/aspnet/Security/issues/59

"Son bir açıklama: iç istisnayı her zaman bir ve içinde istisna olarak kullanmaktan kaçınmalı Task.Resultve iletiyi genel bir tanesiyle değiştirmelisiniz (Bir veya daha fazla hata oluştu), bu da hata ayıklamayı zorlaştırıyor. Bu kadar sık ​​kullanılmazsa, bunun yerine kullanmayı kesinlikle düşünmelisiniz . "Task.WaitAggregateExceptionTask.GetAwaiter().GetResult()


20
Burada atıfta bulunulan kaynak, referans olmadan başka birinden alıntı yapan birisidir. Bağlamı düşünün: Bunu okuduktan sonra her yerde GetAwaiter (). GetResult () kullanarak körü körüne birçok insan görebiliyorum.
Jack Ukleja

2
Yani kullanmamalıyız?
tofutim

11
İki görev bir istisna ile sona ererse, bu senaryoda ikincisini kaybedersiniz Task.WhenAll(task1, task2).GetAwaiter().GetResult();.
Monsignor


33

Bir başka fark, asyncişlev sadece döner Taskyerine Task<T>o zaman kullanımı olamaz

GetFooAsync(...).Result;

Buna karşılık

GetFooAsync(...).GetAwaiter().GetResult();

hala çalışıyor.

Sorudaki örnek kodun durum için olduğunu biliyorum Task<T>, ancak soru genellikle sorulur.


1
Bu doğru değil. Tam olarak bu yapıyı kullanan kemanımı kontrol
wojciech_rak

3
Kodunuzda @wojciech_rak, kullandığınız Resultile GetIntAsync()hangi döner Task<int>sadece Task. Cevabımı tekrar okumanızı tavsiye ederim.
Nuri Tasdemir

1
Haklısın, ilk başta geri dönen bir fonksiyonun GetFooAsync(...).Result içinde olamayacağını söylediğini anladım Task. Bu artık mantıklıdır, çünkü C # 'da hiç boşluk özelliği yoktur ( Task.Resultbir özelliktir), ancak elbette bir boşluk yöntemi çağırabilirsiniz.
wojciech_rak

22

Daha önce de belirtildiği gibi kullanabilirsiniz await. Eğer söz gibi eşzamanlı kod çalıştırmasına gerekiyorsa .GetAwaiter().GetResult(), .Resultya .Wait()kilitlenmeleri için bir risktir birçok yorum / cevaplarında söylediğimiz gibi. Çoğumuz onelinerleri sevdiğimiz için bunları.Net 4.5<

Zaman uyumsuz bir yöntemle bir değer elde etme:

var result = Task.Run(() => asyncGetValue()).Result;

Eşzamanlı olarak bir eşzamansız yöntem çağırıyor

Task.Run(() => asyncMethod()).Wait();

Kullanımı nedeniyle kilitlenme sorunu oluşmaz Task.Run.

Kaynak:

https://stackoverflow.com/a/32429753/3850405


1

Bir görev hata verirse, devam kodu awaiter.GetResult () öğesini çağırdığında kural dışı durum yeniden atılır. GetResult'u çağırmak yerine, görevin Result özelliğine erişebiliyorduk. GetResult'u çağırmanın yararı, görev başarısız olursa, istisnanın AggregateException içine sarılmadan doğrudan atılması ve daha basit ve daha temiz catch bloklarına izin vermesidir.

Normal olmayan görevler için GetResult () yöntemi geçersiz bir dönüş değerine sahiptir. Yararlı işlevi yalnızca istisnaları yeniden incelemektir.

Kaynak: Özetle c # 7.0

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.