| کانال توسعه‌دهندگان سی‌شارپ |
1.03K subscribers
19 photos
3 videos
21 links
⭕️ کانال توسعه‌دهندگان سی‌شارپ دولوپیکس

💠 دولوپیکس | جامعه توسعه‌دهندگان ایرانی

💎 @Developix
🚀 Developix.ir

📌 پشتیبانی و تبلیغات:
@DevelopixSupport
Download Telegram
تفاوت <Task <T و <ValueTask<T

همونطور که میدونید هر عملیات Asynchronous نیازمند یک return type از نوع Task هست، اما یک نوع دیگه هم به اسم ValueTask وجود داره که احتمالا قبلا دیدید.
این ابجکت درواقع یک Discriminated Union هست که به زبان ساده، میتونه چندین type مختلف از دیتا رو در خودش نگه داری کنه، که توی زبان هایی مثل Typescript, Rust, FSharp و ... وجود داره، البته کار ValueTask نگه داری چند type مختلف برای شما نیست! اما چرا این type وجود داره ؟
این تابع رو تصور کنید:

async Task<int> GetFollowers(string? username)
{
    if (string.IsNullOrEmpty(username))
        return -1;

    if (!_validateRegex.IsMatch(username))
        return -2;
   
    return await GetInstagramFollowers(username);
}
زیاد پیچیده نیست، صرفا یک username به عنوان ورودی میگیره و تعداد فالور های اون کاربر رو برمیگردونه؛
اما کد ما چه مسیر هایی رو میتونه طی کنه ؟
خب ممکنه در مرحله اول ورودی ما خالی یا null باشه که با شرط اول کد تموم میشه؛
ممکنه خالی نباشه اما یک username معتبر نباشه که توی شرط دوم برسی میشه و کد دوباره تموم میشه

و حالت خوشحال کننده که username معتبر هست و فالور های اون به کاربر نشون داده میشه؛

- خب، اینا چه ربطی به ValueTask داشت ؟

ربطی نداشت واقعا، اما پیش زمینه بود؛ چند تا از این مسیر ها ، به کد asynchronous ختم میشه ؟ فقط یکیشون!
همون مسیر خوشحال کننده که درنهایت یک درخواست احتمالا به API یا DB فرستاده میشه، اما ما برای هر سه مسیر داریم یک Task برمیگردونیم!

- خب، مشکلش چیه؟

هیچ مشکلی نداره، مشکل جایی به وجود میاد که این متد صد ها هزار بار یا بیشتر صدا زده بشه، برای هر بار اجرای این متود، شما یک ابجکت اضافه، جدای از تعداد فالور های کاربر ذخیره میکنید، بله خود Task که از آسمون نازل نمیشه، اون هم داخل Heap ذخیره میشه درست مثل بقیه Object ها، اون هم درصورتی که اینجا ما فقط توی یک مسیر ازش استفاده کردیم، درواقع دو مسیر دیگه، منابع اضافه مصرف میکنن!!
و خب اینکار در دنیای ما، جنایت به حساب میاد؛ اما اینجاست که ValueTask به دردمون میخوره، اگه تابع شما به جای Task ، صرفا ValueTask برگردونه، در دو مسیر دیگه که کد به درخواست asynchronous منتهی نمیشن، صرفا مقدار خالص رو به شما میده، و در مسیر اخری که کد ما به await کردن و درخواست I/O میرسه، یک Task به شما برمیگردونه.

درواقع در لایه زیرین شما همچین چیزی دارید:
ValueTask<Task<T>,T>
که یا میتونه T باشه یا <Task <T

اگر واقعا Task اتون به خطوط async برسه، یک Task دارید، و اگر صرفا در مراحل قبل از اون به اتمام برسه، یک T به صورت مستقیم دارید:
async ValueTask<int> GetFollowersAsync(string? username)
{
    if (string.IsNullOrEmpty(username))
        return -1; //int

    if (!_validateRegex.IsMatch(username))
        return -2; //int
   
    return await GetInstagramFollowers(username); //Task<int>
}
درنتیجه، شما در دو مسیر، از مصرف بیخود منابع جلوگیری میکنید، که توی تعداد درخواست های بالا میتونه زندگیتون رو نجات بده؛
کاربرد های مختلفی برای ValueTask وجود داره، از معروف هاش میشه به سیستم caching اشاره کرد، اما صرفا شرط ساده ای که باید به خاطر بسپارید:

"اگر کد، چندین مسیر مختلف داره و بعضی از اون مسیر ها میتونن به کد async یا sync منتهی بشن، ValueTask میتونه مورد خوبی برای بهینه کردن کد باشه"

و البته محدودیت هایی هم برای استفادش وجود داره:

-برخلاف Task ها، ValueTask ها نباید بیشتر از 1 بار await بشن!
-بیشتر از 1 بار نباید از AsTask بر روی ValueTask استفاده کنید!
-استفاده از Result. یا ()GetAwaiter().GetResult زمانی که هنوز عملیات به اتمام نرسیده یا بیشتر از یک بار استفاده بشن( کلا از اینها هیچوقت استفاده نکنید، چه Task و چه ValueTask )

#performance #async #task

👤 QWxp

💎 Channel: @DevelopixCSharp
👍14👎31
در سی‌شارپ، توابعی که خروجی Task دارند ولی از کلمه‌کلیدی async درآن‌ها استفاده نشده در واقع sync هستند.
در مثالی که در تصویر میبینید شاید تصور شود که متد Example باید در پس زمینه اجرا شود، ولی این اتفاق نمی‌افتد و کاملا به صورت sync اجرا خواهد شد. این تابع در واقع مثل بقیه‌ تابع های sync فقط یک خروجی Task دارد، مثل تابع زیر:
static string Example()

#Task
#Async

👤 Mahdiyar

💎 Channel: @DevelopixCSharp
👍121🔥1