Task va uning jenerik sherigi Task<TResult> klasi ancha vaqtlardan beri bor va har bir .NETchi asinxron dasturlash uchun uni ishlatib ko’rgan. .NET Core 2.0dan boshlab yangi klas ValueTask va ValueTask<TResult> olib kirildi. Ho’sh siz ulardan qaysi birini ishlatishingiz kerak?
Qisqa qilib aytganda, agarda siz kutubxona yozayotgan bo’lsangiz va shu kutubxona xotirani va resurslarni judayam kam sarflashi zarur bo’lgan joylarda ishlatilsa, siz ValueTask haqida bosh qotirsangiz arziydi. Lekin ValueTask ishlatishda judayam extiyotkor bo’lish kerak. Odatiy kunlik ishlarda esa Senior darajada bo’lmagan dasturchilar Task klasi ishlatgani ma’qul.
Ushbu postni oxirigacha o’qib tushinib olganingizdan keyin darajangizdan qatiy nazar ValueTask va Taskni qayerda va qanday ishlatishni tushinib olasiz.
Task/Task<TResult>Task klasining vaziflari ko’p. Qisqa qilib aytganda u uzoq vaqt davom etadigan ish qaytaradigan ma’lumotni o’rash uchun wrapper sifatida ishlatiladi va promise ya’ni va’da deyiladi. Qaytarilgan Task obyektini hohlagan vaqtda await qilib kutib turgan holda natijasini olsa bo’ladi. Bundan tashqari shu obyektni hohlagancha qayta-qayta yoki parallel bir nechta threadda await qilsa ham bir xil natija qaytaradi. Bu judaham kuchli yechim!
async Task<int> GetNaturalGasPriceInUsdAsync()
{
await Task.Delay(1000);
return 9;
}
var uzbekNaturalGasPrice = GetNaturalGasPriceInUsdAsync();
var price = await uzbekNaturalGasPrice;
var price2 = await uzbekNaturalGasPrice;
Yuqoridagi kodda ko’rinib turibdiki bitta Task obyektini bir necha marta await qilish mumkin va u bir xil natija qaytaradi.
Unda muammo nimada? Gap shundaki, Task va Task<TResult> klas tiplar bo’lib har safar asinxron funksiya chaqirilganda Task yoki Task<TResult> allocate (xotirani o’zlashtirish) qilib qaytarishga to’g’ri keladi. Hullas, har safar funksiya chaqirilganda yangi instance yaratib qaytarish dastur tezligi va xotira samaradorligiga sezilarli ta’sir qiladi.
Runtimedagi yechimlarKo’p hollarda asinxron funksiyalar sodda bo’ladi va ularni bir marta await orqali chaqirish kifoya bo’ladi.
...
await SendEmailAsync(email, cancellationToken);
...
Bundan tashqari, ko’p hollarda asinxron funksiya ham ishini sinxron tugatadi ya’ni quyidagi misoldagidek ma’lum shartlar bajarilsagina asinxron ish bajariladi yo’qsa funksiya ishini sinxron tugatib Task qaytaradi.
public async Task SendEmailAsync(Email email, CancellationToken cancellationToken = default)
{
if(email is not null)
await client.SendEmailAsync(email, cancellationToken);
logger.LogInformation("Email not sent!");
}
Ushbu koddan tushinish mumkinki ba’zi hollarda funksiya hech qanday asinxron ish bajarilmaydi.
Bunday holatlar juda ham ko’p takrorlangani uchun .NET Runtime o’zi Taskning hech qanday asinxron ish bajarilmaganda qaytariladigan nusxasini Cache qilib oladi va qayta-qayta ishlataveradi. Bu o’sha biz bilgan Task.CompletedTask obyekti. Yuqoridagi kodda agar email null bo’lsa Runtime o’zi Task.CompletedTaskni cachedan olib qaytaradi. Agar asinxron ish bajarilsa, yangi Task obyekti allocate qilib qaytariladi.