国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

探索c#之Async、Await剖析

2019-11-17 02:19:11
字體:
來源:轉載
供稿:網友

探索c#之Async、Await剖析

2015-06-15 08:35 by 蘑菇先生, ... 閱讀, ... 評論, 收藏, 編輯

閱讀目錄:

  1. 基本介紹
  2. 基本原理剖析
  3. 內部實現剖析
  4. 重點注意的地方
  5. 總結

基本介紹

Async、Await是net4.x新增的異步編程方式,其目的是為了簡化異步程序編寫,和之前APM方式簡單對比如下。

APM方式,BeginGetRequestStream需要傳入回調函數,線程碰到BeginXXX時會以非阻塞形式繼續執行下面邏輯,完成后回調先前傳入的函數。

    HttpWebRequest myReq =(HttpWebRequest)WebRequest.Create("http://VEVb.com/");     myReq.BeginGetRequestStream();     //to do

Async方式,使用Async標記Async1為異步方法,用Await標記GetRequestStreamAsync表示方法內需要耗時的操作。主線程碰到await時會立即返回,繼續以非阻塞形式執行主線程下面的邏輯。當await耗時操作完成時,繼續執行Async1下面的邏輯

static async void Async1()    {        HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create("http://VEVb.com/");        await myReq.GetRequestStreamAsync();        //to do    }     

上面是net類庫實現的異步,如果要實現自己方法異步。APM方式:

        public delegate int MyDelegate(int x);           MyDelegate mathDel = new MyDelegate((a) => { return 1; });         mathDel.BeginInvoke(1, (a) => { },null);

Async方式:

static async void Async2()    {        await Task.Run(() => { Thread.Sleep(500); Console.WriteLine("bbb"); });        Console.WriteLine("ccc");    }  Async2();  Console.WriteLine("aaa");

對比下來發現,async/await是非常簡潔優美的,需要寫的代碼量更少,更符合人們編寫習慣。 因為人的思維對線性步驟比較好理解的。

APM異步回調的執行步驟是:A邏輯->假C回調邏輯->B邏輯->真C回調邏輯,這會在一定程度造成思維的混亂,當一個項目中出現大量的異步回調時,就會變的難以維護。Async、Await的加入讓原先這種混亂的步驟,重新撥正了,執行步驟是:A邏輯->B邏輯->C邏輯。

基本原理剖析

作為一個程序員的自我修養,刨根問底的好奇心是非常重要的。 Async剛出來時會讓人有一頭霧水的感覺,await怎么就直接返回了,微軟怎么又出一套新的異步模型。那是因為習慣了之前的APM非線性方式導致的,現在重歸線性步驟反而不好理解。 學習Async時候,可以利用已有的APM方式去理解,以下代碼純屬虛構。比如把Async2方法想象APM方式的Async3方法:

static async void Async3()    {        var task= await Task.Run(() => { Thread.Sleep(500); Console.WriteLine("bbb"); });       //注冊task完成后回調        task.RegisterCompletedCallBack(() =>        {            Console.WriteLine("ccc");        });    }

上面看其來就比較好理解些的,再把Async3方法想象Async4方法:

static  void Async4()    {        var thread = new Thread(() =>         {             Thread.Sleep(500);             Console.WriteLine("bbb");         });        //注冊thread完成后回調        thread.RegisterCompletedCallBack(() =>        {            Console.WriteLine("ccc");        });        thread.Start();    }

這樣看起來就非常簡單明了,連async都去掉了,變成之前熟悉的編程習慣。雖然代碼純屬虛構,但基本思想是相通的,差別在于實現細節上面。

內部實現剖析

作為一個程序員的自我修養,嚴謹更是不可少的態度。上面的基本思想雖然好理解了,但具體細節呢,編程是個來不得半點虛假的工作,那虛構的代碼完全對不住看官們啊。

繼續看Async2方法,反編譯后的完整代碼如下:

internal class PRogram{    // Methods    [AsyncStateMachine(typeof(<Async2>d__2)), DebuggerStepThrough]    private static void Async2()    {        <Async2>d__2 d__;        d__.<>t__builder = AsyncVoidMethodBuilder.Create();        d__.<>1__state = -1;        d__.<>t__builder.Start<<Async2>d__2>(ref d__);    }    private static void Main(string[] args)    {        Async2();        Console.WriteLine("aaa");        Console.ReadLine();    }    // Nested Types    [CompilerGenerated]    private struct <Async2>d__2 : IAsyncStateMachine    {        // Fields        public int <>1__state;        public AsyncVoidMethodBuilder <>t__builder;        private object <>t__stack;        private TaskAwaiter <>u__$awaiter3;        // Methods        private void MoveNext()        {            try            {                TaskAwaiter awaiter;                bool flag = true;                switch (this.<>1__state)                {                    case -3:                        goto Label_00C5;                    case 0:                        break;                    default:                        if (Program.CS$<>9__CachedAnonymousMethodDelegate1 == null)                        {                            Program.CS$<>9__CachedAnonymousMethodDelegate1 = new Action(Program.<Async2>b__0);                        }                        awaiter = Task.Run(Program.CS$<>9__CachedAnonymousMethodDelegate1).GetAwaiter();                        if (awaiter.IsCompleted)                        {                            goto Label_0090;                        }                        this.<>1__state = 0;                        this.<>u__$awaiter3 = awaiter;                        this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.<Async2>d__2>(ref awaiter, ref this);                        flag = false;                        return;                }                awaiter = this.<>u__$awaiter3;                this.<>u__$awaiter3 = new TaskAwaiter();                this.<>1__state = -1;            Label_0090:                awaiter.GetResult();                awaiter = new TaskAwaiter();                Console.WriteLine("ccc");            }            catch (Exception exception)            {                this.<>1__state = -2;                this.<>t__builder.SetException(exception);                return;            }        Label_00C5:            this.<>1__state = -2;            this.<>t__builder.SetResult();        }        [DebuggerHidden]        private void SetStateMachine(IAsyncStateMachine param0)        {            this.<>t__builder.SetStateMachine(param0);        }    }    public delegate int MyDelegate(int x);} Collapse Methods 
View Code

發現async、await不見了,原來又是編譯器級別提供的語法糖優化,所以說async不算是全新的異步模型。 可以理解為async更多的是線性執行步驟的一種回歸,專門用來簡化異步代碼編寫。從反編譯后的代碼看出編譯器新生成一個繼承IAsyncStateMachine的狀態機結構asyncd(代碼中叫<Async2>d__2,后面簡寫AsyncD),下面是基于反編譯后的代碼來分析的

IAsyncStateMachine最基本的狀態機接口定義:

public interface IAsyncStateMachine{    void MoveNext();    void SetStateMachine(IAsyncStateMachine stateMachine);}

既然沒有了async、await語法糖的阻礙,就可以把代碼執行流程按線性順序來理解,其整個執行步驟如下:

1. 主線程調用Async2()方法2. Async2()方法內初始化狀態機狀態為-1,啟動AsyncD3. MoveNext方法內部開始執行,其task.run函數是把任務扔到線程池里,返回個可等待的任務句柄。MoveNext源碼剖析:

//要執行任務的委托

 Program.CS$<>9__CachedAnonymousMethodDelegate1 = new Action(Program.<Async2>b__0);

//開始使用task做異步,是net4.0基于任務task的編程方式。

 awaiter =Task.Run(Program.CS$<>9__CachedAnonymousMethodDelegate1).GetAwaiter();

//設置狀態為0,以便再次MoveNext直接break,執行switch后面的邏輯,典型的狀態機模式。

this.<>1__state = 0;

//返回調用async2方法的線程,讓其繼續執行主線程后面的邏輯

this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Program.<Async2>d__2>(ref awaiter, ref this);return;

4. 這時就已經有2個線程在跑了,分別是主線程和Task.Run在跑的任務線程。

5. 執行主線程后面邏輯輸出aaa,任務線程運行完成后輸出bbb、在繼續執行任務線程后面的業務邏輯輸出ccc。

Label_0090: awaiter.GetResult(); awaiter = new TaskAwaiter();Console.WriteLine("ccc");

這里可以理解為async把整個主線程同步邏輯,分拆成二塊。 第一塊是在主線程直接執行,第二塊是在任務線程完成后執行, 二塊中間是任務線程在跑,其源碼中awaiter.GetResult()就是在等待任務線程完成后去執行第二塊。 從使用者角度來看執行步驟即為: 主線程A邏輯->異步任務線程B邏輯->主線程C邏輯。

        Test();        Console.WriteLine("A邏輯");        static async void Test()        {            await Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("B邏輯"); });            Console.WriteLine("C邏輯");         }

回過頭來對比下基本原理剖析小節中的虛構方法Async4(),發現區別在于一個是完成后回調,一個是等待完成后再執行,這也是實現異步最基本的兩大類方式。

重點注意的地方

主線程A邏輯->異步任務線程B邏輯->主線程C邏輯。

注意:這3個步驟是有可能會使用同一個線程的,也可能會使用2個,甚至3個線程。可以用Thread.CurrentThread.ManagedThreadId測試下得知。

     Async7();     Console.WriteLine(Thread.CurrentThread.ManagedThreadId);     static async void Async7()    {        await Task.Run(() =>        {            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);         });        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);     }

正由于此,才會有言論說Async不用開線程,也有說需要開線程的,從單一方面來講都是對的,也都是錯的。 上面源碼是從

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 子洲县| 溆浦县| 汶上县| 布拖县| 旌德县| 新乡市| 德阳市| 海伦市| 绥芬河市| 新邵县| 富顺县| 泸州市| 海安县| 太原市| 平度市| 长兴县| 怀宁县| 斗六市| 乌兰察布市| 菏泽市| 山阳县| 寿阳县| 黄山市| 济源市| 涪陵区| 吴旗县| 新巴尔虎右旗| 鄂伦春自治旗| 尼勒克县| 宜都市| 乾安县| 文化| 南江县| 博爱县| 大丰市| 封开县| 金平| 栾城县| 镇原县| 南康市| 巴南区|