Async/await hádanky

Ondřej Janáček       3. 8. 2014       C#, .NET       4813 zobrazení

Narazil jsem na pár hádanek ohledně async/await z .NET 4.5, kde u některých není řešení ihned očividné. Zkuste si je projít, příští týden přidám vysvětlení a řešení pro ověření, proto prosím vydržte s Vašimi řešeními až do té doby. Jakmile budou na stole otázky i odpovědi, můžeme je rozebrat. Kousky kódu si klidně vložte do VS a vyzkoušejte. Tam, kde je metoda pojmenována button1_Click je pro kýžený výsledek doporučeno opravdu testovat v GUI aplikaci.

Proč mi zase zamrzlo UI?

async void button1_Click(...)
{
    Action work = CPU work;
    await ScheduleAsync(work);
}

async Task ScheduleAsync(Action work)
{
    work();
}

Proč to proběhlo rychleji, než chci? - 1

...
Task.Delay(1000);
...

Proč to proběhlo rychleji, než chci? - 2

...
await Task.Factory.StartNew(
    async () => { await Task.Delay(1000); });
...

Tak kdy už to skončí? - 1

async void button1_Click(...)
{
    FooAsync().Wait();
}

async Task FooAsync()
{
    await Task.Delay(1000);
}

Tak kdy už to skončí? - 2

async void button1_Click(...)
{
    var result = await Foo();    
}

Task<int> Foo()
{
    var tcs = new TaskCompletionSource<int>();
    Task.Run(delegate
    {
        int result = Bar();
        tcs.SetResult(result);
    });
    return tcs.Task;
}

Zde najdete řešení a vysvětlení.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

Řešení

Nezkoušel jsem to z Visual Studia, ale můj odhad je:

Proč mi zase zamrzlo UI?

- async/await nezajišťuje automaticky paralelizaci, slouží pouze pro usnadnění práce s Task objektem a zpětnou synchronizací - tady celý kód proběhl synchronně v hlavním vlákně protože i přes použití "await" se uvnitř metody vše provedlo synchronně (žádné čekání na awaitable objekt)

Proč to proběhlo rychleji, než chci? - 1

- Tento příkaz nečeká, ale vytváří objekt Task, který bude označen za dokončený až po předaném intervalu, viz: http://msdn.microsoft.com/cs-cz/library/...

Proč to proběhlo rychleji, než chci? - 2

- Tahle úloha mi chvilku trvala. Příkaz StartNew spustí task předaný delegátem a vrací jeho výsledek. V tomhle případě ale vrací Task<Task> protože vnitřní volání je asynchronní a má tedy výsledek Task. A metoda await vyčká na dokončení tasku Task<Task> a vrátí jeho výsledek, tedy vnitřní Task, který reprezentuje čekání. Nikdo ale už nečeká na dokončení tohoto vnitřního Tasku. Myslím, že zavolání "await" dvakrát za sebou by mohlo fungovat a čekalo by se i na dokončení výsledku metody Delay.

Tak kdy už to skončí? - 1

- Tady záleží na sychronizačním kontextu a vlákno, ze kterého je událost vyvoláná. V případě formulářových aplikací (smyčka zpráv) dojde k deadlocku, protože hlavní vlákno je blokované a synchronně čeká (metoda Wait) na dokončení tasku. Ten task ale uvnitř po dokončení úlohy čekání snaží předat vykonávání synchronizačním kontextem na hlavní vlákno, což ale není možné, protože smyčka hlavního vlákna je blokovaná.

Tak kdy už to skončí? - 2

- Tady nevidím žádný problém.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Také jsem nezkoušel ve VS.

Jen drobné doplnění:

Proč mi zase zamrzlo UI? - tady by měl kompilátor vyhodit warning, že metoda ScheduleAsync proběhne synchronně, protože v ní není žádné await.

Proč to proběhlo rychleji, než chci? - 2 - To je přesně rozdíl mezi Task.Factory.StartNew a Task.Run. S Task.Run by to fungovalo, protože ten vnitřní Task "vybalí".

Tak kdy už to skončí? - 2 - také nevidím problém.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

Příspěvky zaslané pod tento článek se neobjeví hned, ale až po schválení administrátorem.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback