Zaman uyumsuz programlama kod tabanı üzerinden "büyür". Bu edilmiş bir zombi virüsü ile karşılaştırıldığında . En iyi çözüm büyümesine izin vermektir, ancak bazen bu mümkün değildir.
Ben Nito.AsyncEx benim birkaç tür yazdımKısmen eşzamansız kod tabanı ile uğraşmak için kütüphanemde . Yine de her durumda çalışan bir çözüm yok.
Çözüm A
Bağlamına geri senkronize edilmesi gerekmeyen basit bir eşzamansız yönteminiz varsa, şunları kullanabilirsiniz Task.WaitAndUnwrapException:
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
Sen do not kullanmak istediğiniz Task.Waitveya Task.Resultonlar istisnalar sarın çünkü AggregateException.
Bu çözüm yalnızca MyAsyncMethodiçeriğiyle senkronize edilmezse uygundur . Bir başka deyişle, her awaityer MyAsyncMethodbitmelidir ConfigureAwait(false). Bu, herhangi bir UI öğesini güncelleyemeyeceği veya ASP.NET istek içeriğine erişemeyeceği anlamına gelir.
Çözüm B
Eğer MyAsyncMethodkendi bağlamına senkronize arkasına ihtiyacı da artar, ardından kullanmak mümkün olabilir AsyncContext.RunTaskyuvalanmış bir bağlam sağlamak için:
var result = AsyncContext.RunTask(MyAsyncMethod).Result;
* Güncelleme 4/14/2014: Kütüphanenin daha yeni sürümlerinde API aşağıdaki gibidir:
var result = AsyncContext.Run(MyAsyncMethod);
( Task.ResultBu örnekte kullanmak uygun , çünkü RunTaskyayılacakTask İstisnalar ).
Bunun AsyncContext.RunTaskyerine ihtiyaç duymanızın nedeni Task.WaitAndUnwrapException, WinForms / WPF / SL / ASP.NET'te gerçekleşen oldukça ince bir kilitlenme olasılığıdır:
- Eşzamanlı bir yöntem, a
Task.
- Eşzamanlı yöntem, üzerinde engelleme beklemesi yapar
Task.
asyncYöntemini kullanır awaitolmadan ConfigureAwait.
TaskZaman sadece tamamlar, çünkü bu durumda tamamlayamıyor asyncyöntem bitmiş olduğu; asyncyöntem tam değil onun devamını planlamak için çalışıyor çünkü SynchronizationContext, ve WinForms / WPF / SL / ASP.NET senkron yöntem zaten bu bağlamda çalışıyor çünkü devamı çalışmasına izin vermeyecektir.
Bu, ConfigureAwait(false)her asyncyöntemde mümkün olduğunca kullanılmasının iyi bir fikir olmasının bir nedenidir .
Çözüm C
AsyncContext.RunTaskher senaryoda çalışmaz. Örneğin, asyncyöntem tamamlanması için bir UI olayı gerektiren bir şey beklerse, iç içe bağlamda bile kilitleneceksiniz. Bu durumda, asyncyöntemi thread havuzunda başlatabilirsiniz :
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
Ancak, bu çözüm MyAsyncMethodiş parçacığı havuzu bağlamında çalışacak bir gerektirir . Bu yüzden UI öğelerini güncelleyemez veya ASP.NET istek içeriğine erişemez. Ve bu durumda, siz de ekleyebilirsiniz ConfigureAwait(false)için onunawait tabloların ve çözüm A'yı kullanmak
Güncelleme, 2019-05-01: Geçerli "en kötü uygulamalar" burada bir MSDN makalesinde bulunmaktadır .