搜尋
首頁後端開發C#.Net教程C#非同步之APM模式非同步程式開發的範例分享

C#已有10多年歷史,單從微軟2年一版的更新進度來看活力異常旺盛,C#中的非同步程式設計也經歷了多個版本的演化,從今天起手寫一個系列博文,記錄一下C#中的非同步程式設計的發展歷程。 廣告一下:喜歡我文章的朋友,請點下面的「追蹤我」。謝謝

我是2004年接觸並使用C#的,那時C#版本為1.1,所以我們就從就那個時候談起。那時在大學裡自己看書寫程序,所寫的程序大都是同步程序,最多啟動個線程........其實在C#1.1的時代已有完整的非同步編程解決方案,那就是APM (非同步程式設計模型)。如果還有不了解「同步程式、非同步程式」的請自行百度哦。

APM非同步程式設計模型最具代表性的特點是:一個非同步功能由以Begin開頭、End開頭的兩個方法組成。 Begin開頭的方法表示啟動非同步功能的執行,End開頭的方法表示等待非同步功能執行結束並傳回執行結果。下面是一個模擬的實作方式(後面將寫標準的APM模型非同步實作):

public class Worker
    {        
    public int A { get; set; }        
    public int B { get; set; }        
    private int R { get; set; }
        ManualResetEvent et;        
        public void BeginWork(Action action)
        {
            et = new ManualResetEvent(false);            
            new Thread(() =>
            {
                R = A + B;
                Thread.Sleep(1000);
                et.Set();                
                if(null != action)
                {
                    action();
                }
            }).Start();
        }        public int EndWork()
        {            if(null == et)
            {                t
            hrow new Exception("调用EndWork前,需要先调用BeginWork");
            }            
            else
            {
                et.WaitOne();                
                return R;
            }

        } 
    }
        static void Main(string[] args)
        {
           Worker w = new Worker();
            w.BeginWork(()=> {
                Console.WriteLine("Thread Id:{0},Count:{1}", Thread.CurrentThread.ManagedThreadId,
                    w.EndWork());
            });
            Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }

在上面的類比APM模型中我們使用了Thread、ManualResetEvent,如果你對多執行緒和ManualResetEvent不熟悉C#中使用非同步程式設計不可避免的會涉及到多執行緒的知識,雖然微軟在Framework中做了很多封裝,但朋友們應該掌握其本質。

上面模擬的APM非同步模型之所以簡單,是因為在C#發展過程中引入了許多優秀的語法規則。上例我們較多的使用了Lambda表達式,如果你不熟悉 匿名委託與lambda表達式可看我之前的Bolg《匿名委託與Lambda表達式》。上面做瞭如此多的廣告,下面我們來看看標準的APM模型如何實現非同步程式設計。

IAsyncResult介面

IAsyncResult介面定義了非同步功能的狀態,此介面具體屬性及意義如下:

   //     表示异步操作的状态。
    [ComVisible(true)]    public interface IAsyncResult
    {        //
        // 摘要:        //     获取一个值,该值指示异步操作是否已完成。        //
        // 返回结果:        //     如果操作已完成,则为 true;否则为 false。
        bool IsCompleted { get; }        //
        // 摘要:        //     获取用于等待异步操作完成的 System.Threading.WaitHandle。        //
        // 返回结果:        //     用于等待异步操作完成的 System.Threading.WaitHandle。
        WaitHandle AsyncWaitHandle { get; }        //
        // 摘要:        //     获取一个用户定义的对象,该对象限定或包含有关异步操作的信息。        //
        // 返回结果:        //     一个用户定义的对象,限定或包含有关异步操作的信息。
        object AsyncState { get; }        //
        // 摘要:        //     获取一个值,该值指示异步操作是否同步完成。        //
        // 返回结果:        //     如果异步操作同步完成,则为 true;否则为 false。
        bool CompletedSynchronously { get; }
    }

#注意:模型範例1中的ManualResetEvent 繼承自WaitHandle
APM傳說實作方式
在了解了IAsyncResult介面後,我們來透過實作IAsyncResult 介面的方式完成模擬範例的改寫工作,程式碼如下:

    public class NewWorker
    {        public class WorkerAsyncResult : IAsyncResult
        {
            AsyncCallback callback;            
            public WorkerAsyncResult(int a,int b, AsyncCallback callback, object asyncState) {
                A = a;
                B = b;
                state = asyncState;                
                this.callback = callback;                
                new Thread(Count).Start(this);
            }            
            public int A { get; set; }            
            public int B { get; set; }            
            public int R { get; private set; }            
            private object state;            
            public object AsyncState
            {                
            get
                {                    
                return state;
                }
            }            
            private ManualResetEvent waitHandle;            
            public WaitHandle AsyncWaitHandle
            {                
            get
                {                    
                if (null == waitHandle)
                    {
                        waitHandle = new ManualResetEvent(false);
                    }                    
                    return waitHandle;
                }
            }            private bool completedSynchronously;            
            public bool CompletedSynchronously
            {                get
                {                    
                return completedSynchronously;
                }
            }            
            private bool isCompleted;            
            public bool IsCompleted
            {                
            get
                {                    
                return isCompleted;
                }
            }            
            private static void Count(object state)
            {                
            var result = state as WorkerAsyncResult;
                result.R = result.A + result.B;
                Thread.Sleep(1000);
                result.completedSynchronously = false;
                result.isCompleted = true;
                ((ManualResetEvent)result.AsyncWaitHandle).Set();                
                if (result.callback != null)
                {
                    result.callback(result);
                }
            }
        }        
        public int Num1 { get; set; }        
        public int Num2 { get; set; }        
        public IAsyncResult BeginWork(AsyncCallback userCallback, object asyncState)
        {
            IAsyncResult result = new WorkerAsyncResult(Num1,Num2,userCallback, asyncState);            
            return result;
        }        public int EndWork(IAsyncResult result)
        {
            WorkerAsyncResult r = result as WorkerAsyncResult;
            r.AsyncWaitHandle.WaitOne();            return r.R;
        }
    }

範例程式碼分析:

上面程式碼中NewWorker的內部類別 WorkerAsyncResult 是關鍵點,它實作了IAsyncResult 介面並由它來負責開啟新執行緒完成運算工作。

在WorkerAsyncResult中增加了 A、B兩個私有屬性來儲存用於計算的數值,一個對外可讀不可寫的屬性R,用於儲存WorkerAsyncResult內部運算的結果。 AsyncWaitHandle屬性由 ManualResetEvent 來充當,並在首次訪問時創建ManualResetEvent(但不釋放)。其他介面屬性正常實現,沒有什麼可說。

WorkerAsyncResult 中新增 static Count 方法,參數 state 是呼叫Count方法的目前WorkerAsyncResult物件。 Count 方法在 WorkerAsyncResult 物件的新啟執行緒中運行,因此Thread.Sleep(1000)將阻塞新執行緒1秒中。然後設定目前WorkerAsyncResult物件是否同步完成為false,非同步完成狀態為true,釋放ManualResetEvent通知以便等待執行緒取得通知進入執行狀態,判斷是否有非同步執行結束回呼委託,存在則回調之。

NewWorker 非常簡單,Num1、Num2兩個屬性為要計算的數值。 BeginWork 建立WorkerAsyncResult物件、並將要計算的兩個數值Num1、Num2、userCallback回呼委託、object 類型的 asyncState 傳入要建立的WorkerAsyncResult物件。經過此步驟操作,WorkerAsyncResult物件取得了運算所需的所有資料、運算完成後的回呼,並馬上啟動新執行緒進行運算(執行WorkerAsyncResult.Count方法)。

因為WorkerAsyncResult.Count執行在新執行緒中,在該執行緒外部無法準確獲知新執行緒的狀態。為了滿足外部執行緒與新執行緒同步的需求,在NewWorker中增加EndWork方法,參數類型為IAsyncResult。要呼叫EndWork方法應傳入BeginWork 取得的WorkerAsyncResult對象,EndWork方法應傳入BeginWork 取得的WorkerAsyncResult對象,EndWork方法取得WorkerAsyncResult物件後,呼叫WorkerAsyncResult.AsyncWaitHandle.WaitOne()方法,等待取得ManualResetEvent通知,在取得到結束時運算並已取得執行緒運算),下一步取得運算結果R並返回。

接下來是NewWorker呼叫程序,如下:

        static void Main(string[] args)
        {
            NewWorker w2 = new NewWorker();
            w2.Num1 = 10;
            w2.Num2 = 12;
            IAsyncResult r = null;
            r = w2.BeginWork((obj) => {
            Console.WriteLine("Thread Id:{0},Count:{1}",Thread.CurrentThread.ManagedThreadId,
            w2.EndWork(r));
            }, null);
            Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadLine();
        }

#下圖我簡單畫的程式呼叫過程,有助於各位朋友理解:

標準的APM模型非同步編程,對應開發人員來說過於複雜。因此透過實作 IAsyncResult 介面進行非同步編程,就是傳說中的中看不中用(罪過.....)。

Delegate非同步程式設計(APM 標準實作)

C#中委托天生支持异步调用(APM模型),任何委托对象后"."就会发现BeginInvoke、EndInvoke、Invoke三个方法。BeginInvoke为异步方式调用委托、EndInvoke等待委托的异步调用结束、Invoke同步方式调用委托。因此上面的标准APM实例,可借助  delegate 进行如下简化。

上面NewWorker使用委托方式改写如下:

<br/>


    public class NewWorker2
    {
        Func<int> action;        public NewWorker2()
        {
            action = new Func<int>(Work);
        }        public IAsyncResult BeginWork(AsyncCallback callback, object state)
        {            dynamic obj = state;            return action.BeginInvoke(obj.A, obj.B, callback, this);
        }        public int EndWork(IAsyncResult asyncResult)
        {            try
            {                return action.EndInvoke(asyncResult);
            }            catch (Exception ex)
            {                throw ex;
            }
        }        private int Work(int a, int b)
        {
            Thread.Sleep(1000);            return a + b;
        }
    }</int></int>

调用程序:

        static void Main(string[] args)
        {
            NewWorker2 w2 = new NewWorker2();
            IAsyncResult r = null;
            r = w2.BeginWork((obj) =>
            {
                Console.WriteLine("Thread Id:{0},Count:{1}", Thread.CurrentThread.ManagedThreadId,
                    w2.EndWork(r));
            }, new { A = 10, B = 11 });
            Console.WriteLine("Thread Id:{0}", Thread.CurrentThread.ManagedThreadId);

            Console.ReadLine();
        }

上面的使用委托进行APM异步编程,比实现 IAsyncResult 接口的方式精简太多、更易理解使用。因此这里建议朋友们 delegate 异步调用模型应该掌握起来,而通过实现 IAsyncResult 接口的传说方式看你的喜好吧。 

以上是C#非同步之APM模式非同步程式開發的範例分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
c#.net適合您嗎?評估其適用性c#.net適合您嗎?評估其適用性Apr 13, 2025 am 12:03 AM

c#.netissutableforenterprise-levelapplications withemofrosoftecosystemdueToItsStrongTyping,richlibraries,androbustperraries,androbustperformance.however,itmaynotbeidealfoross-platement forment forment forment forvepentment offependment dovelopment toveloperment toveloperment whenrawspeedsportor whenrawspeedseedpolitical politionalitable,

.NET中的C#代碼:探索編程過程.NET中的C#代碼:探索編程過程Apr 12, 2025 am 12:02 AM

C#在.NET中的編程過程包括以下步驟:1)編寫C#代碼,2)編譯為中間語言(IL),3)由.NET運行時(CLR)執行。 C#在.NET中的優勢在於其現代化語法、強大的類型系統和與.NET框架的緊密集成,適用於從桌面應用到Web服務的各種開發場景。

C#.NET:探索核心概念和編程基礎知識C#.NET:探索核心概念和編程基礎知識Apr 10, 2025 am 09:32 AM

C#是一種現代、面向對象的編程語言,由微軟開發並作為.NET框架的一部分。 1.C#支持面向對象編程(OOP),包括封裝、繼承和多態。 2.C#中的異步編程通過async和await關鍵字實現,提高應用的響應性。 3.使用LINQ可以簡潔地處理數據集合。 4.常見錯誤包括空引用異常和索引超出範圍異常,調試技巧包括使用調試器和異常處理。 5.性能優化包括使用StringBuilder和避免不必要的裝箱和拆箱。

測試C#.NET應用程序:單元,集成和端到端測試測試C#.NET應用程序:單元,集成和端到端測試Apr 09, 2025 am 12:04 AM

C#.NET應用的測試策略包括單元測試、集成測試和端到端測試。 1.單元測試確保代碼的最小單元獨立工作,使用MSTest、NUnit或xUnit框架。 2.集成測試驗證多個單元組合的功能,常用模擬數據和外部服務。 3.端到端測試模擬用戶完整操作流程,通常使用Selenium進行自動化測試。

高級C#.NET教程:ACE您的下一次高級開發人員面試高級C#.NET教程:ACE您的下一次高級開發人員面試Apr 08, 2025 am 12:06 AM

C#高級開發者面試需要掌握異步編程、LINQ、.NET框架內部工作原理等核心知識。 1.異步編程通過async和await簡化操作,提升應用響應性。 2.LINQ以SQL風格操作數據,需注意性能。 3..NET框架的CLR管理內存,垃圾回收需謹慎使用。

C#.NET面試問題和答案:提高您的專業知識C#.NET面試問題和答案:提高您的專業知識Apr 07, 2025 am 12:01 AM

C#.NET面試問題和答案包括基礎知識、核心概念和高級用法。 1)基礎知識:C#是微軟開發的面向對象語言,主要用於.NET框架。 2)核心概念:委託和事件允許動態綁定方法,LINQ提供強大查詢功能。 3)高級用法:異步編程提高響應性,表達式樹用於動態代碼構建。

使用C#.NET建築微服務:建築師實用指南使用C#.NET建築微服務:建築師實用指南Apr 06, 2025 am 12:08 AM

C#.NET是構建微服務的熱門選擇,因為其生態系統強大且支持豐富。 1)使用ASP.NETCore創建RESTfulAPI,處理訂單創建和查詢。 2)利用gRPC實現微服務間的高效通信,定義和實現訂單服務。 3)通過Docker容器化微服務,簡化部署和管理。

C#.NET安全性最佳實踐:防止常見漏洞C#.NET安全性最佳實踐:防止常見漏洞Apr 05, 2025 am 12:01 AM

C#和.NET的安全最佳實踐包括輸入驗證、輸出編碼、異常處理、以及身份驗證和授權。 1)使用正則表達式或內置方法驗證輸入,防止惡意數據進入系統。 2)輸出編碼防止XSS攻擊,使用HttpUtility.HtmlEncode方法。 3)異常處理避免信息洩露,記錄錯誤但不返回詳細信息給用戶。 4)使用ASP.NETIdentity和Claims-based授權保護應用免受未授權訪問。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具