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

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

學習迭代器實現C#異步編程——仿async/await(一)

2019-11-17 03:18:56
字體:
來源:轉載
供稿:網友

學習迭代器實現C#異步編程——仿async/await(一)

2014-03-08 23:08 by 樓上那個蜀黍, ... 閱讀, ... 評論, 收藏, 編輯

  .NET 4.5的async/await真是個神奇的東西,巧妙異常以致我不禁對其實現充滿好奇,但一直難以窺探其門徑。不意間讀了此篇強文《Asynchronous PRogramming in C# using Iterators》,猶如醍醐灌頂,茅廁頓開,思路猶如尿崩。美玉不敢獨享,故寫此篇,將所學中一些思考與諸君共享,期拋磚引玉,擦出一些基情火花……

  強文《Asynchronous Programming in C# using Iterators》出自大牛,大牛眼界高遠。故文中所述較為簡略,而文中所附代碼亦較為晦澀,鄙人駑鈍,反復閱讀思考數十遍,方品出些味道。故本篇會對原文代碼一個最簡化的提取,再進行分析。

  強文提到的用迭代器在C#中進行異步編程,最核心的思想就是通過yield return產生一個可IEnumerable<Asyncable>的集合,取出第一個Asyncable,執行Async方法并立即返回,將控制權交給上層調用方,同時Async方法在完成后會回調MoveNext繼續遍歷之前集合。(本篇提到的最底層的Async方法均是以Begin/End來實現,之前的隨筆也說過async/await只是語法糖)

  大概畫了個草圖意思一下,花了很久時間也沒能畫得特別清晰明了,請見諒,有好的想法還望賜教。

  接下來我們根據具體的代碼來分析,首先看一下Main方法。第一行是一個異步方法,我們期待的結果是第二行的輸出在異步方法結束前執行。

        static void Main(string[] args)        {            AsyncMethod("http://www.microsoft.com").Execute();            Console.WriteLine("我先執行,不等你了");            Console.ReadLine();        }

  AsyncMethod方法返回了一個IEnumerable<IAsync>的集合,這里需要注意的是AsyncMethod方法的返回值其實是一個類似狀態機的類對象,這個對象本身不會執行內部的代碼語句,我們需要一個Execute方法來開始遍歷運行這個集合里的代碼語句。而AsyncMethod方法里的語句又根據yield return的個數來劃分成塊,每一次MoveNext方法其實是執行一塊的代碼。也就是說存在多少個yield return,就會有多少次回調。

  

        static IEnumerable<IAsync> AsyncMethod(string url)        {            WebRequest req = HttpWebRequest.Create(url);            Console.WriteLine("[{0}] starting", url);            // asynchronously get the response from http server            Async<WebResponse> response = req.GetResponseAsync();            yield return response;            Console.WriteLine("[{0}] got response", url);            Stream resp = response.Result.GetResponseStream();            foreach (var item in resp.ReadToEndAsync())            {                yield return item;            }            Console.WriteLine("done");        }

  GetResponseAsync方法看上去很簡單,就是封裝了一下Beginxx/Endxxx。為什么說看上去簡單,后面會提到。AsyncPrimitive就是我們會接觸到最底層的Asyncable對象了,本篇一切異步都是基于它來實現的。

        public static Async<WebResponse> GetResponseAsync(this WebRequest req)        {            return new AsyncPrimitive<WebResponse>(req.BeginGetResponse, req.EndGetResponse);        }

  ReadToEndAsync和AsyncMethod方法一樣,是建立在可返回Async<T>對象的已有Async方法的基礎上。

        public static IEnumerable<IAsync> ReadToEndAsync(this Stream stream)        {            MemoryStream ms = new MemoryStream();            int read = -1;            while (read != 0)            {                byte[] buffer = new byte[512];                Async<int> count = stream.ReadAsync(buffer, 0, 512);                yield return count;                Console.WriteLine("[{0}] got data: {1}", "url", count.Result);                ms.Write(buffer, 0, count.Result);                read = count.Result;            }        }

  ReadAsync同樣是通過Beginxxx/Endxxx來實現異步。他和GetResponseAsync一樣是建立在AsyncPrimitive對象上的Async方法。

        public static Async<int> ReadAsync(this Stream stream, byte[] buffer, int offset, int count)        {            return new AsyncPrimitive<int>(                (callback, st) => stream.BeginRead(buffer, offset, count, callback, st),                stream.EndRead);        }

  下面讓我們重點來看一下AsyncPrimitive類,你可能已經發現這個類和Task<T>.Factory.FromAsync方法有點相似。可是如果讓自己來實現,怕不是想象的那么簡單。

    public class AsyncPrimitive<T> : Async<T>    {        Action<Action<T>> func;        public AsyncPrimitive(Func<AsyncCallback, object, IAsyncResult> begin, Func<IAsyncResult, T> end)        {            this.func = (cont) => begin(delegate(IAsyncResult res) { cont(end(res)); }, null);        }        public override void ExecuteStep(Action cont)        {            func((res) =>            {                result = res;                completed = true;                cont();            });        }    }

  完全由委托、匿名方法和lambda表達式組成的類。在ExecuteStep被調用前,它不會做任何事情,僅僅是構建了一個Action<Action<T>>的委托。那么分析這個類才是本篇最主要的目的,但難點在于這貨不是三言兩語就能說清楚的,鄙人在暈乎了很久很久以后,將該類翻譯如下,去除了所有的匿名方法和lambda表達式。看明白了這個類,就明白了通過迭代器是如何實現異步的。

    public class AsyncPrimitive<T> : Async<T>    {        Action<Action<T>> func;        public AsyncPrimitive(Func<AsyncCallback, object, IAsyncResult> begin, Func<IAsyncResult, T> end)        {            this.Begin = begin;            this.End = end;            this.func = this.ActionActionT;        }        Func<IAsyncResult, T> End { get; set; }        Func<AsyncCallback, object, IAsyncResult> Begin { get; set; }        Action<T> RunInCallback { get; set; }        Action ActionOuter {get;set;}        private void Callback(IAsyncResult ar)        {            this.RunInCallback(this.End(ar));        }        private void ActionActionT(Action<T> cont)        {            this.RunInCallback = cont;            this.Begin(this.Callback, null);        }        private void ActionT(T res)        {            this.result = res;            this.completed = true;            this.ActionOuter();        }        public override void ExecuteStep(Action cont)        {            this.ActionOuter = cont;            this.func(this.ActionT);        }    }

  直觀的就可以感覺到lambda幫助我們省略了多少代碼,在簡潔的同時,也增加了些許理解的難度。代碼就是最好的注釋,我實在沒信心去用文字描述這個類如何工作。

  最后補充Execute方法,這個方法真正的開始執行Async方法,大體思路就是遍歷集合,但不是通過while循環,而是通過callback來執行下一個MoveNext。

        public static void Execute(this IEnumerable<IAsync> async)        {            AsyncExtensions.Run(async.GetEnumerator());        }        internal static void Run(IEnumerator<IAsync> en)        {            if (!en.MoveNext()) return;            en.Current.ExecuteStep                (() => AsyncExtensions.Run(en));        }

  附上可運行的工程供調試用。原文鏈接開頭已給出,原文中也給出了原文代碼的下載。推薦都下載比對著看,可能會更有幫助。

  本篇也是初寫的時候信心滿滿,不知道被各位吐槽后會是怎樣一副情景……之后還應該還會有第二篇,也許是明天,也許是明年……

代碼下載


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 科技| 共和县| 娱乐| 漠河县| 锦州市| 洛南县| 金坛市| 普格县| 清新县| 桦甸市| 宜春市| 上饶县| 吉木乃县| 手机| 方正县| 南乐县| 泰州市| 宣化县| 赣州市| 巴南区| 长宁区| 陇西县| 沾益县| 盐山县| 汤原县| 二连浩特市| 辉南县| 柯坪县| 南郑县| 曲阜市| 启东市| 太康县| 商河县| 涿州市| 平罗县| 昭通市| 浦县| 尖扎县| 永川市| 奇台县| 曲麻莱县|