關於C#異步編程的代碼筆記

異步學習代碼筆記

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

namespace ConsoleApp7
{
    class Program
    {
        [STAThread]
        static void  Main(string[] args)//三個方法如果同步執行需要16s,而採用異步方式不僅主線程不會被阻塞,執行完也只需要10s,因爲他們是並行執行的
        {
            Console.WriteLine("Main_" + Thread.CurrentThread.ManagedThreadId);
            Coffee cup = PourCoffee();
            Console.WriteLine("coffee is ready_"+DateTime.Now);
            Task<Egg> eggs = FryEggs(2);//1s
            Console.WriteLine("eggs are ready_"+DateTime.Now);
            Task<Bacon> bacon =  FryBacon(3);//5s
            Console.WriteLine("bacon is ready_" + DateTime.Now);
            Task<Toast> toast = ToastBreadAsync1(2);//10s
            Toast result1 = toast.Result;
            Bacon result2 = bacon.Result;
            Egg resul3 = eggs.Result;
            Console.WriteLine("toast is ready_" + DateTime.Now);
            Juice oj = PourOJ();
            Console.WriteLine("oj is ready");
            Console.WriteLine("Breakfast is ready!");
            Console.ReadLine();
        }


        private static Juice PourOJ()
        {
            return new Juice();
        }

        private async static Task<Toast> ToastBreadAsync1(int v)//需要依賴返回值進行進一步的處理則需要封裝成async異步方法,以便await結果進行後續處理
        {
            Toast toast = await ToastBread(v);
            ApplyButter(toast);//相當於回調的代碼
            ApplyJam(toast);//相當於回調的代碼
            return toast;
        }
        private static Task<Toast> ToastBread(int v)//供ToastBreadAsync1封裝成異步方法
        {
            return  Task<Toast>.Factory.StartNew(()=> { Thread.Sleep(1000); Console.WriteLine("Toast_" + Thread.CurrentThread.ManagedThreadId); return new Toast(); });
        }

        private static Task<Bacon> FryBacon(int v)//如果無需關心返回值則調用方直接調用任務方法而無需封裝成async異步方法
        {
            return Task<Bacon>.Factory.StartNew(() => { Thread.Sleep(5000); Console.WriteLine("Bacon_"+Thread.CurrentThread.ManagedThreadId); return new Bacon(); });
        }

        private static Task<Egg> FryEggs(int v)//如果無需關心返回值則調用方直接調用任務方法而無需封裝成async異步方法
        {
            return  Task<Egg>.Factory.StartNew(() => { Thread.Sleep(10000);Console.WriteLine("Eggs_"+Thread.CurrentThread.ManagedThreadId); return new Egg(); });
        }

        private static void ApplyJam(Toast toast)//類似回調的方法
        {
            Thread.Sleep(3000);
            Console.WriteLine("ApplyJam finished_" + DateTime.Now);
        }

        private static void ApplyButter(Toast toast)//類似回調的方法
        {
            Thread.Sleep(3000);
            Console.WriteLine("ApplyButter finished_" + DateTime.Now);
        }

    

        private static Coffee PourCoffee()
        {
            Console.WriteLine("Start PourCoffee");
            return new Coffee();
        }
    }

    internal class Toast
    {
    }

    internal class Coffee
    {
    }

    //要點1:創建Task除了可以用new+手動start,還可以通過Task<Egg>.Factory.StartNew()實現;
    //要點2:如上帶有返回值的異步方法ToastBreadAsync1的返回值與return的值類型是不一樣的。
    //且其返回的Task<Toast>爲其包含內部兩個同步方法ApplyButter/ApplyJam的Task<Toast>,
    //而不單純是 await ToastBread(v)返回的Task
    //要點3:當調用異步方法的Task.Result時會阻塞線程。調用Task.wait()顯式阻塞線程.
    //在web開發中假設需要調用多個接口獲取返回值合併輸出到web頁面時的場景會用到線程阻塞。
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章