مروری بر Async Await در #C

چهارشنبه 5 آبان 1395

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

مروری بر  Async Await در #C

آماده سازی فضای برنامه نویسی :

در این مقاله ما از Visual Studio 2015 استفاده خواهیم کرد . برای شروع کار، ابتدا Visual Studio را باز کنید :


در مرحله بعد ، یک Console Application با نام AsyncSample ایجاد کنید :

بعد ایجاد پروژه فضای برنامه نویسی ما همانند تصویر زیر  خواهد بود : 



قبل از شروع به کدنویسی و ایجاد برنامه با یکسری از کلمات کلیدی بیشتر آشنا خواهیم شد :

Async : ما برای اینکه مشخص کنیم که یک متد Asynchronous است از معرف asynv استفاده میکنیم . توافقات بر این منوال است که اینگونه متد ها را async method بنامیم .

Await : عملگر await به یک task در یک متد async اطلاق میشود ، که باعث میشود تا زمان اتمام یافتن آن task ، اجرای متد به حالت تعلیق دربیاید . عملگر await فقط در متدهایی قابل استفاده میباشند که دارای async modifier باشند .

نکته : توجه داشته باشید که ما تعاریف کلمات کلیدی فوق را بصورت ساده و روان بیان کردیم . شما میتوانید برای کسب اطلاعات بیشتر و دیدن تعریفات رسمی تر به سایت msdn.microsoft.com مراجعه فرمایید .

اولین متد Asynchronous :
در این قسمت ، به سراغ کد نویسی میرویم . کد زیر را در visual studio جایگذاری کنید :

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AsyncSample
{
    class Program
    {
        static void Main(string[] args)
        {
            Loop();

            Console.WriteLine("End of Work ...");
            Console.ReadKey();
        }

        public static async void Loop()
        {
             for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine(i);    
            }
        }
    }
}

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




خروجی این برنامه بسیار ساده میباشد ، ما اعداد 1 تا 10 را در خروجی مشاهده خواهیم کرد و در آخر هم جمله End of Work ظاهر خواهد شد .

زمانی که برنامه برای اتمام این فراخوانی منتظر مانده بود ، برنامه Main مسدود شده بود و تا زمانی که کار حلقه for به اتمام برسد . اگر برنامه شما ، یک برنامه تحت desktop بود در همچین وضعیتی برنامه شما به حالت freez میرفت و در این حالت کاربر تصور میکرد که برنامه هنگ کرده و به مشکلی برخورده است در حالی که حقیقت چیز دیگریست و برنامه منتظر است تا حلقه به اتمام برسد . 

مراحل برنامه نویسی Asynchronous با Async Await :

حال به سراغ نوشتن کدی در مُد Async میرویم . اولین چیزی که مورد نیاز است ، راهی برای وارد کرد پشته Asynchronous است . در برنامه desktop همچین کاری به عنوان یک event handler میباشد که در ازای کلیک یک دکمه اجرا میشود . اگرچه ، برای این برنامه ، ما کد زیر را در نظر میگیریم :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AsyncSample
{
    class Program
    {
        static void Main(string[] args)
        {
            ThisWouldNormallyBeAnEventHandler();
            Console.WriteLine("End of line...");

            Console.ReadKey();
        }

        public static async void ThisWouldNormallyBeAnEventHandler()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i);
                await Task.Delay(1);
            }
        }
    }
}

به عنوان یک قانون ، async void برای event handlerها یا متد های سطح بالا هستند که اجازه پردازش به Asynchronous method میدهند . در Console Application این اجازه به متد main داده نمیشود که async باشد برای همین ما از async void method برای وارد کردن asynchronous stack استفاده میکنیم .

حال برنامه را برای مشاهده خروجی آن اجرا کنید :




اتفاقی که در کد می‌افتد بدین صورت است که بعد از ایجاد تاخیر در حلقه ، برنامه متوقف نمیشود بلکه به سراغ ادامه کد در main میرود و آن را به صورت async اجرا میکند . حال 

await Task.Delay(1);

و نتیجه را مشاهده کنید . زمانی که خطی را حذف می‌کنید دارای کلمه کلیدی await است  و متد آن هنوز دارای کلمه کلیدی async است ، این متد همچنان syncronous کار میکند . که احتمالا InteliSnce زیر نام متد خط کشیده و به شما هشداری را خواهد داد که منظور آن این است که در اینجا یک متد async وجود دارد که دارای کلمه کلیدی await نیست .

در ادامه در مورد ()Task.Delay صحبت خواهیم کرد . 

نوع بازگشتی 'Task 'the Awaitable :

حال ، به متد async با نوع بازگشتی void نگاهی بیندازید . حال هدف این بخش این است ، که نوع داده ای غیر از void را بازگردانیم ، برای این کار شما میتوانید همانند زیر عمل کنید :


    public  static void Main()
        {
            ThisWouldNormallyBeAnEventHandler();
            Console.WriteLine("End of line...");

            Console.ReadKey();
        }

        public static async void ThisWouldNormallyBeAnEventHandler()
        {
            await LoopAsync();
        }

        public static async Task LoopAsync()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i);
                await Task.Delay(1);
            }
        }


برعکس async void که awaitable نبود ، متد ()LoopAsync یک متدی است که میتوان از کلمه کلیدی await برای آن استفاده کرد ، همین امر ()ThisWouldNormallyBeAnEventHandler را قادر به suspend کردن اجرای برنامه تا زمان کامل شدن متد ()LoopAsync میکند . در راستای همین امر ، همانند مثال قبلی که ارائه شد ، ادامه متد Main ما اجرا میشود . 

به این نکته توجه داشته باشید که نام متد ما Loop است و بنا به قرارداد نام گذاری برای متدهای asyn به انتهای نام متد خود یک Async اضافه میکنیم . که نشان میدهد که این متد واقعا Async میباشد .
بخاطره مقاله ما ، متد ما asynchronous است و دلیل آن await در ()Task.Delay میباشد . در برنامه های واقعی ، این میتواند یک source را از اینترنت دانلود کند و شما میخواهید در زمان دانلود نیز با برنامه کار کنید . 

پیرو قولی که در مورد توضیح ()Task.Delay داده بودیم ، در این مرحله به توضیح آن میپردازیم  .
یک راه ثانویه عالی برای استفاده از ()Thread.Sleep میباشد . آن non-blocking است و در مدت durationای که شما آن را مشخص میکنید ، thread که باید اجرا شود ، فراخوانی میشود . زمانی که duration ای که آن به اتمام رسید ، به نقطه ای بازمیگردد که در آنجا فراخوانی شده بود . دقیقا برعکس Thread.Sleep ، که تمام اجراهای Thread ای که در آن است را Suspend میکند . 

یک نگاه سریع و اجمالی هم به <Task<T میندازیم . اگر شما قصد دارید که متد شما مقداری با نوع Boolean باز گرداند..همانند زیر عمل کنید :

async Task<bool> LoopAsync()

زمانی که یک استاندارد مقدار true را بازمیگرداند . کار میکند . اگرچه ، این فقط زمانی کار میکند که متد با کلمه کلیدی modify ، async شده باشد . Taskهای دیگری نیز وجود دارد که این مقاله پتانسیل کافی برای ارائه شدن آنها را ندارد و در مقاله های بعدی آن هارا ارائه خواهیم داد . Async Task در کد ، در مقابل Async voidها ، مثل آب خوردن میباشند . Async Void ها با استفاده از event handler ها به شما اجازه دسترسی به stack را میدهند ، در ضمن ، Async voidها منطق کنترل خطای متفاوتی با Async Task ها دارند . 

آموزش سی شارپ

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان
  • C#.net
  • 2k بازدید
  • 3 تشکر

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید