C# async constructors

Kun async/await julkaistiin C# koodiin siitä seurasi hyviä asioita ja joitakin ongelmia. Niiden avulla saadaan käyttöliittymä vastaamaan käyttäjän syötteisiin nopeammin. Kyse ei ole kuitenkaan oikeasta moniajosta, koska kaikki tapahtuu UI säikeessä. Vasta Task.Run() avulla saadaan oikean moniajon hyödyt irti. Tässä jutussa kerron miten itse olen ratkaissut await kutsun konstruktorissa. Normaalisti siellä suoritetaan koodia, minkä pitää olla valmis ennen kuin luokkaa käytetään. Ongelmaa ei ole jos valmistumista ei tarvitse odottaa ja kutsu ei palauta mitään. Seuraavassa esimerkissä ei odoteta eikä palauteta mitään. Koska kyseessä on void eikä Task metodin suoritus sitä ei odoteta.

public MainPage()
{
Doit()
}
private async void Doit()
{
await DoAsync();
}

DoAsync valmistuu joskus sen jälkeen kun konstruktori on valmis. Mutta monessa apissa nykyään tarvitaan await kutsuja. Kun paluuarvoja tarvitaan konstructorissa, pitää tuloksia odottaa ja tarvitaan hieman lisää koodia.

public MainPage()
{
var task = Task.Run(async () =>
{
return await DoAsync();
});
double result = Task.WhenAll(task).Result[0];
}

Nyt async koodi ajetaan konstruktorissa ja lopputulos saadaan talteen. Seuraavassa ajetaan monta async kutsua rinnakkaisesti ja otetaan lopputulokset talteen. Tämä on nopeampi tapa kuin UI säikeessä tapahtuva ajo.

List<Task> tasks = new List<Task>();
for (int i = 0; i
{
return await DoAsync();
}));
}
double all = 0.0;
foreach (var result in Task.WhenAll(tasks).Result)
{
all += result;
}

Tätä samaa tekniikkaa voi hyödyntää kun async alkaa ’kuplimaan’ luokissa ylöspäin. Sillä saa katkaistua nousun kun luokkakirjaston syövereissä joutuu käyttämään await kutsua. Await ei sitten näy kirjaston käyttäjälle. Tämäkään ei ole ”kultainen vasara” kaikkeen, varsinkin jos tällä tavoin ajettavassa koodissa esimerkiksi ajetaan Dispatcherin kanssa koodia UI säikeessä saadaan aikaiseksi deadlock.

Yksi kommentti artikkeliin ”C# async constructors

Jätä kommentti