در توسینسو تدریس کنید

و

با دانش خود درآمد کسب کنید

آموزش کلمات کلیدی async و await در زبان سی شارپ

تا این لحظه از مجموعه مطالب مرتبط با مباحث Asynchronous Programming در سی شارپ با ماهیت Asynchronous در delegate ها، کار با Thread ها و کتابخانه TPL در دات نت آشنا شدیم. اما باز هم در برخی سناریو ها و انجام کارهای پیچیده در برنامه نویسی Asynchronous، نیاز به حجم زیادی از کدها وجود دارد. از نسخه 4.5 دات، در زبان سی شارپ (و همینطور زبان VB) دو کلمه کلیدی اضافه شد که اجازه نوشتن کدهای Asynchronous را به شکل دیگری به برنامه نویسان می داد. این دو کلمه کلیدی، کلمات async و await هستند و زمانی که شما در کدهای خود از این دو کلمه کلیدی استفاده می کنید، در زمان کامپایل کدها، کامپایلر کدهایی را برای شما تولید می کند که به صورت بهینه و البته مطمئن کارهای Asynchronous را برای شما انجام می دهند، کدهای تولید شده از کلاس هایی که در فضای نام System.Threading.Tasks قرار دارند استفاده می کنند.

نگاه اولیه با ساختار async و await

زمانی که شما در بخشی از کد خود از کلمه کلیدی async و بر روی متدها، عبارات لامبدا یا متدهای بدون نام استفاده می کنید، در حقیقت می گویید که این قطعه کد به صورت خودکار باید به صورت Asynchronous فراخوانی شود و زمان استفاده از کدی که به صورت async تعریف شده، CLR به صورت خودکار thread جدیدی ایجاد کرده و کد را اجرا می کند. اما زمان فراخوانی کدهایی که به صورت async تعریف شده اند، استفاده از کلمه await این امکان را فراهم می کند که اجرای thread جاری تا زمان تکمیل اجرای کدی که به صورت async تعریف شده، می بایست متوقف شود. برای آشنایی بیشتر برنامه ای از نوع Windows Forms Application ایجاد کرده، یک Button بر روی فرم قرار می دهیم. زمانی که بر روی Button ایجاد شده کلیک می شود، یک متد دیگر فراخوانی شده و بعد از یک وقفه 10 ثانیه ای عبارتی را بر میگرداند و در نهایت این متن به عنوان Title برای فرم برنامه ست می شود:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }

    private void CallButton_Click(object sender, EventArgs e)
    {
        this.Text = DoWork();
    }

    private string DoWork()
    {
        Thread.Sleep(10000);
        return "Done.";
    }
}

مشکلی که وجود دارد این است که بعد از کلیک بر روی Button ایجاد شده، 10 ثانیه باید منتظر شده تا عنوان فرم تغییر کند. اما با انجام یکسری تغییرات در کد بالا، می توان بوسیله کلمات کلیدی async و await کاری کرد که عملیات اجرای متد به صورت Asynchronous انجام شود. برای اینکار کد بالا را به صورت زیر تغییر می دهیم:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }

    private async void CallButton_Click(object sender, EventArgs e)
    {
        this.Text = await DoWork();
    }

    private Task DoWork()
    {
        return Task.Run(() =>
        {
            Thread.Sleep(10000);
            return "Done.";
        });
    }
}

بعد از اجرای برنامه، خواهیم دید که فرم ما به قول معروف block نمی شود، یعنی تا زمان اتمام فراخوانی DoWork می توانیم کارهای دیگری در فرم انجام دهیم. اگر در کد بالا دقت کنید، متدی که برای رویداد Click دکمه CallButton تعریف شده، با کلمه کلیدی async مشخص شده، یعنی اجرای این متد باید به صورت Aynchronous انجام شود، علاوه بر این، داخل بدنه این متد، زمان فراخوانی DoWork از کلمه await استفاده کردیم، دقت کنید که نوشتن کلمه کلیدی await اینجا الزامی است، اگر این کلمه کلیدی نوشته نشود، زمان اجرای DoWork باز هم عملیات فراخوانی متد باعث block شدن فرم ما می شود. همچنین دقت کنید که متد DoWork به جای اینکه مقدار string برگرداند، مقداری از نوع

زمانی که متد DoWork فراخوانی می شود، یک Task جدید اجرا می شود و داخل Task ابتدا عملیات اجرای Thread به مدت 10 ثانیه متوقف می شود و بعد از 10 ثانیه یک رشته به عنوان خروجی برگردانده می شود. البته این رشته تحت یک شئ از نوع Task به متدی که DoWork را فراخوانی کرده بازگردانده می شود.با تعریف بالا، شاید بتوان بهتر نقش کلمه کلیدی await را متوجه شد، زمانی که برنامه به کلمه کلیدی await می رسد، در حقیقت منتظر می ماند تا عملیات فراخوانی متدی که await قبل از آن نوشته شده به اتمام برسد، سپس مقدار خروجی از داخل Task مربوطه برداشته شده و داخل خصوصیت Text قرار داده می شود.

قواعد نام گذاری برای متدهای Async

همانطور که گفتیم، داخل متدهایی که با async مشخص شده اند، حتماً می بایست کلمه کلیدی await نیز نوشته شود. اما از کجا بدانیم کدام متدها می توانند به صورت Async فراخوانی شوند؟ یعنی نوع خروجی آن ها یک Task است؟ اصطلاحاً به متدهایی که خروجی آن ها از نوع

private async Task DoWorkAsync()
{
    return await Task.Run(() =>
    {
        Thread.Sleep(10000);
        return "Done.";
    });
}

با انجام تغییرات بالا، کد رویداد Click را برای CallButton به صورت زیر تغییر می دهیم:

private async void CallButton_Click(object sender, EventArgs e)
{
    this.Text = await DoWorkAsync();
}

متدهای Async با مقدار خروجی void


در صورتی که متدی که قرار است به صورت async فراخوانی شود، مقدار خروجی ندارد می توان نوع خروجی متد را از نوع کلاس غیر جنریک Task انتخاب کرد و کلمه کلیدی return را ننوشت:

        private async Task DoWorkAsync()
        {
            await Task.Run(() =>
            {
                Thread.Sleep(10000);
            });
        }

فراخوانی این متد نیز به صورت زیر خواهد بود:

await DoWorkAsync();
MessageBox.Show("Done.");

متدهای async با چندین await


یکی از قابلیت های async و await، نوشتن چندین قسمت await در یک متد async است. نمونه کد زیر حالت گفته شده را نشان می دهد:

private async void CallButton_Click(object sender, EventArgs e)
{
    await Task.Run(() => { Thread.Sleep(5000); });
    MessageBox.Show("First Task Done!");

    await Task.Run(() => { Thread.Sleep(5000); });
    MessageBox.Show("Second Task Done!");

    await Task.Run(() => { Thread.Sleep(5000); });
    MessageBox.Show("Third Task Done!");
}

دقت کنید که برای await های بالا متدی تعریف نکردیم و تنها در مقابل آن متد Run از کلاس Task را فراخوانی کردیم. البته این موضوع ربطی به چند await بودن متد ندارد و شما می تواند متد هایی که خروجی آن ها از نوع Task است را نیز فراخوانی کنید، این حالت تنها برای مثال به این صورت نوشته شده است.

با اتمام این بخش از آموزش و آشنایی با کلمات async و await، بحث ما در مورد برنامه نویسی Asynchronous نیز به پایان می رسد. امیدوارم که این سری آموزشی مورد توجه شما دوستان عزیز قرار گرفته باشد. ITPRO باشید

نویسنده: حسین احمدی

منبع: جزیره برنامه نویسی و توسعه نرم افزار وب سایت توسینسو

هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است

#آموزش_سی_شارپ #متدهای_asynchronous_در_سی_شارپ #async_و_await_در_سی_شارپ #برنامه_نویسی_asynchronous #task_ها_در_سی_شارپ #کلمه_کلیدی_async_در_سی_شارپ
عنوان
1 آموزش برنامه نویسی موازی سی شارپ قسمت 1 : Task Parallel Library رایگان
2 آموزش برنامه نویسی موازی سی شارپ قسمت 2 : کلاس Task رایگان
3 آموزش برنامه نویسی موازی سی شارپ قسمت 3 : کلاس CancellationToken رایگان
4 آموزش برنامه نویسی موازی سی شارپ قسمت 4 : کوئری Parallel در LINQ رایگان
5 آموزش کلمات کلیدی async و await در زبان سی شارپ رایگان
زمان و قیمت کل 0″ 0
5 نظر
sana.hatami94@gmail.com

عالی بود ... واقعا می گم

محمد مهدی خلیلی

خیلی خیلی عالی٫ ممنون از توضیح عالی.

mfg

Mohammad Mahdi Khalily

mahdicinema

بهترین توضیح برای async و await بود که توی سایتهای فارسی پیدا میشه

ممنون

موفق باشید

hosseinats

سلام من ویدئوی مربوطه را هم نگاه کردم ولی یه مشکلی دارم شما فرض بفرمایید که ما در یک ایونت کلیک asynk بخوایم دو تا await از متدهای task داشته باشیم ، متد دوم صبر میکنه تا متد اول اجرا بشه و بعد مقدار متد دوم رو همراه با متد اول نمایش میده . برای حل این مشکل چیکار میشه کرد ؟

 private async void AsyncBtn_Click(object sender, EventArgs e)
        {
            int[] myArr = new int[] { 4, 8, 5, 6, 2, 5, 6, 7, 2, 8, 9, 7, 8, 12, 13, 11, 10 };
           txtBox.Text = (await DoSumAsync()).ToString();
            txtSecond.Text = (await GetAverageAsync(myArr));

        }

        private Task<long> DoSumAsync()
        {
            return Task.Run<long>(() =>
            {
                var num = Enumerable.Repeat(10, 1000); //Repeat 10 ، 10000 Times'
                long sum= 0;
                foreach (var item in num)
                {
                    System.Threading.Thread.Sleep(2);
                    sum += item;
                }
                return sum;
            });
        }
        private Task<string> GetAverageAsync(int[] myArr)
        {
            return Task.Run<string>(() =>
            {
                long sum = 0;
                foreach (var item in myArr)
                {
                    sum += item;
                }
                return (sum/myArr.Length).ToString();
            });
        }
حسین احمدی

سلام و عرض ادب، شما برای اینکار باید دو تغییر تو کدتون بدید، کار اول اینکه نوع بازگشتی متد GetAverageAsync رو به <Task<long تغییر بدید، و زمان فراخوانی متدها از متد WhenAll به صورت زیر استفاده کنید:

private async void AsyncBtn_Click(object sender, EventArgs e)
{
    int[] myArr = new int[] { 4, 8, 5, 6, 2, 5, 6, 7, 2, 8, 9, 7, 8, 12, 13, 11, 10 };
    var results = await Task.WhenAll(DoSumAsync(), GetAverageAsync(myArr));
    txtBox.Text = results[0].ToString();
    txtSecond.Text = results[1].ToString();

}

private Task<long> DoSumAsync()
{
    return Task.Run<long>(() =>
    {
        var num = Enumerable.Repeat(10, 1000); //Repeat 10 ، 10000 Times'
        long sum = 0;
        foreach (var item in num)
        {
            System.Threading.Thread.Sleep(2);
            sum += item;
        }
        return sum;
    });
}
private Task<long> GetAverageAsync(int[] myArr)
{
    return Task.Run<long>(() =>
    {
        long sum = 0;
        foreach (var item in myArr)
        {
            sum += item;
        }
        return (sum / myArr.Length);
    });
}
نظر شما
برای ارسال نظر باید وارد شوید.
از سرتاسر توسینسو
تنظیمات حریم خصوصی
تائید صرفنظر
×

تو می تونی بهترین نتیجه رو تضمینی با بهترین های ایران بدست بیاری ، پس مقایسه کن و بعد خرید کن : فقط توی جشنواره پاییزه می تونی امروز ارزونتر از فردا خرید کنی ....