Hezký den všem, mám otázku do pléna ohledně návrhu pomocí async/await. Dejme tomu, že máme modelovou situaci a píšu knihovnu, která má poskytovat asynchronní i synchronní variantu nějaké metody. První špatný návrh je:
public class MyClass
{
public async Task MyMethodAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
public void MyMethod()
{
MyMethodAsync().Wait();
}
}
Pokud zavolám sychronní variantu MyMethod z prostředí, kde synchronizační kontext bude chtít požadavek po dokončení vnitřní čekací operace vrátit na hlavní vlákno. To je však blokováno metodou Wait, která nevrátí vykonávání do smyčky zpráv a tak se vytvoří deadlock. Nejjednodušší variantou jak to vyřešit je použítí metody ConfigureAwait(false). Tou oznámím, že po dokončení operace se nemá výsledek vracet do původního synchronizačního kontextu a na dokončení async operace se "vezme" jiné vlákno:
public async Task MyMethodAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
}
Jenže takový postup znamená, že by se muselo ConfigureAwait zapsat všude, kde chci volat await a nezáleží mi, zda se vše vrátí do původního kontextu. Napadají mě i další obskurdní způsoby jako vyrušení kontextu na dobu používání operace, které funguje, ale nevypadá to úplně čistě:
public void MyMethod()
{
var oldContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
try
{
MyMethodAsync().Wait();
}
finally
{
SynchronizationContext.SetSynchronizationContext(oldContext);
}
}
Moje otázka tedy zní - jak to nejlépe řešit? Jak se nejlépe zachovat při návrhu takové knihovny?
|