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.Wait
veya Task.Result
onlar istisnalar sarın çünkü AggregateException
.
Bu çözüm yalnızca MyAsyncMethod
içeriğiyle senkronize edilmezse uygundur . Bir başka deyişle, her await
yer MyAsyncMethod
bitmelidir 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 MyAsyncMethod
kendi bağlamına senkronize arkasına ihtiyacı da artar, ardından kullanmak mümkün olabilir AsyncContext.RunTask
yuvalanmış 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.Result
Bu örnekte kullanmak uygun , çünkü RunTask
yayılacakTask
İstisnalar ).
Bunun AsyncContext.RunTask
yerine 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
.
async
Yöntemini kullanır await
olmadan ConfigureAwait
.
Task
Zaman sadece tamamlar, çünkü bu durumda tamamlayamıyor async
yöntem bitmiş olduğu; async
yö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 async
yöntemde mümkün olduğunca kullanılmasının iyi bir fikir olmasının bir nedenidir .
Çözüm C
AsyncContext.RunTask
her senaryoda çalışmaz. Örneğin, async
yöntem tamamlanması için bir UI olayı gerektiren bir şey beklerse, iç içe bağlamda bile kilitleneceksiniz. Bu durumda, async
yöntemi thread havuzunda başlatabilirsiniz :
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
Ancak, bu çözüm MyAsyncMethod
iş 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 .