c# 異步編程

同步方法和異步方法的區別

同步方法調用在程序繼續執行之前需要等待同步方法執行完畢返回結果
異步方法則在被調用之後立即返回以便程序在被調用方法完成其任務的同時執行其它操作

林sir提示:在異步方法裏面,注意的是回調函數!搞定了回調函數就基本瞭解異步編程。

異步編程的基礎:http://www.cnblogs.com/ericwen/archive/2008/03/12/1101801.html

同步方法和異步方法的區別

同步方法調用在程序繼續執行之前需要等待同步方法執行完畢返回結果
異步方法則在被調用之後立即返回以便程序在被調用方法完成其任務的同時執行其它操作

異步編程概覽

.NET Framework 允許您異步調用任何方法。定義與您需要調用的方法具有相同簽名的委託;公共語言運行庫將自動爲該委託定義具有適當簽名

的 BeginInvoke 和 EndInvoke 方法。

BeginInvoke 方法用於啓動異步調用。它與您需要異步執行的方法具有相同的參數,只不過還有兩個額外的參數(將在稍後描述)。

BeginInvoke 立即返回,不等待異步調用完成。
BeginInvoke 返回 IasyncResult,可用於監視調用進度。

EndInvoke 方法用於檢索異步調用結果。調用 BeginInvoke 後可隨時調用 EndInvoke 方法;如果異步調用未完成,EndInvoke 將一直阻塞到

異步調用完成。EndInvoke 的參數包括您需要異步執行的方法的 out 和 ref 參數(在 Visual Basic 中爲 <Out> ByRef 和 ByRef)以及由

BeginInvoke 返回的 IAsyncResult。

四種使用 BeginInvoke 和 EndInvoke 進行異步調用的常用方法。調用了 BeginInvoke 後,可以:

1.進行某些操作,然後調用 EndInvoke 一直阻塞到調用完成。
2.使用 IAsyncResult.AsyncWaitHandle 獲取 WaitHandle,使用它的 WaitOne 方法將執行一直阻塞到發出 WaitHandle 信號,然後調用

EndInvoke。這裏主要是主程序等待異步方法,等待異步方法的結果。
3.輪詢由 BeginInvoke 返回的 IAsyncResult,IAsyncResult.IsCompeted確定異步調用何時完成,然後調用 EndInvoke。此處理個人認爲與
相同。
4.將用於回調方法的委託傳遞給 BeginInvoke。該方法在異步調用完成後在 ThreadPool 線程上執行,它可以調用 EndInvoke。這是在強制裝

換回調函數裏面IAsyncResult.AsyncState(BeginInvoke方法的最後一個參數)成委託,然後用委託執行EndInvoke。
警告   始終在異步調用完成後調用 EndInvoke。

以上有不理解的稍後可以再理解。

 

例子

1)先來個簡單的沒有回調函數的異步方法例子

請再運行程序的時候,仔細看註釋,對理解很有幫助。還有,若將註釋的中的兩個方法都同步,你會發現異步運行的速度優越性。

 

using System;

 namespace ConsoleApplication1
 {
     class Class1
     {
         //聲明委託
         public delegate void AsyncEventHandler();
 
         //異步方法
         void Event1()
        {
            Console.WriteLine("Event1 Start");
            System.Threading.Thread.Sleep(4000);
            Console.WriteLine("Event1 End");
        }

        // 同步方法
        void Event2()
        {
            Console.WriteLine("Event2 Start");
            int i=1;
            while(i<1000)
            {
                i=i+1;
                Console.WriteLine("Event2 "+i.ToString());
            }
            Console.WriteLine("Event2 End");
        }

        [STAThread]
        static void Main(string[] args)
        {
            long start=0;
            long end=0;
            Class1 c = new Class1();
            Console.WriteLine("ready");
            start=DateTime.Now.Ticks;

            //實例委託
            AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
            //異步調用開始,沒有回調函數和AsyncState,都爲null
            IAsyncResult ia = asy.BeginInvoke(nullnull);
            //同步開始,
            c.Event2();
            //異步結束,若沒有結束,一直阻塞到調用完成,在此返回該函數的return,若有返回值。

           
            asy.EndInvoke(ia);

            //都同步的情況。
            //c.Event1();
            //c.Event2();
           
            end =DateTime.Now.Ticks;
            Console.WriteLine("時間刻度差="+ Convert.ToString(end-start) );
            Console.ReadLine();
        }
    }
}


 

2)下面看有回調函數的WebRequestWebResponse的異步操作。

using System;
using System.NET;
using System.Threading;
using System.Text;
using System.IO;


// RequestState 類用於通過
// 異步調用傳遞數據
public class RequestState
{
    const int BUFFER_SIZE = 1024;
    public StringBuilder RequestData;
    public byte[] BufferRead;
    public HttpWebRequest Request;
    public Stream ResponseStream;
    // 創建適當編碼類型的解碼器
    public Decoder StreamDecode = Encoding.UTF8.GetDecoder();

    public RequestState()
    {
        BufferRead = new byte[BUFFER_SIZE];
        RequestData = new StringBuilder("");
        Request = null;
        ResponseStream = null;
    }
}

// ClientGetAsync 發出異步請求
class ClientGetAsync
{
    public static ManualResetEvent allDone = new ManualResetEvent(false);
    const int BUFFER_SIZE = 1024;

    public static void Main(string[] args)
    {

        if (args.Length < 1)
        {
            showusage();
            return;
        }

        // 從命令行獲取 URI
        Uri HttpSite = new Uri(args[0]);

        // 創建請求對象
        HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(HttpSite);

        // 創建狀態對象
        RequestState rs = new RequestState();

        // 將請求添加到狀態,以便它可以被來回傳遞
        rs.Request = wreq;

        // 發出異步請求
        IAsyncResult r = (IAsyncResult)wreq.BeginGetResponse(new AsyncCallback(RespCallback), rs);

        // 將 ManualResetEvent 設置爲 Wait,
        // 以便在調用回調前,應用程序不退出
        allDone.WaitOne();
    }

    public static void showusage()
    {
        Console.WriteLine("嘗試獲取 (GET) 一個 URL");
        Console.WriteLine("\r\n用法::");
        Console.WriteLine("ClientGetAsync URL");
        Console.WriteLine("示例::");
        Console.WriteLine("ClientGetAsync http://www.microsoft.com/net/");
    }

    private static void RespCallback(IAsyncResult ar)
    {
        // 從異步結果獲取 RequestState 對象
        RequestState rs = (RequestState)ar.AsyncState;

        // 從 RequestState 獲取 HttpWebRequest
        HttpWebRequest req = rs.Request;

        // 調用 EndGetResponse 生成 HttpWebResponse 對象
        // 該對象來自上面發出的請求
        HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(ar);

        // 既然我們擁有了響應,就該從
        // 響應流開始讀取數據了
        Stream ResponseStream = resp.GetResponseStream();

        // 該讀取操作也使用異步完成,所以我們
        // 將要以 RequestState 存儲流
        rs.ResponseStream = ResponseStream;

        // 請注意,rs.BufferRead 被傳入到 BeginRead。
        // 這是數據將被讀入的位置。
        IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);
    }


    private static void ReadCallBack(IAsyncResult asyncResult)
    {
        // 從 asyncresult 獲取 RequestState 對象
        RequestState rs = (RequestState)asyncResult.AsyncState;

        // 取出在 RespCallback 中設置的 ResponseStream
        Stream responseStream = rs.ResponseStream;

        // 此時 rs.BufferRead 中應該有一些數據。
        // 讀取操作將告訴我們那裏是否有數據
        int read = responseStream.EndRead(asyncResult);

        if (read > 0)
        {
            // 準備 Char 數組緩衝區,用於向 Unicode 轉換
            Char[] charBuffer = new Char[BUFFER_SIZE];

            // 將字節流轉換爲 Char 數組,然後轉換爲字符串
            // len 顯示多少字符被轉換爲 Unicode
            int len = rs.StreamDecode.GetChars(rs.BufferRead, 0, read, charBuffer, 0);
            String str = new String(charBuffer, 0, len);

            // 將最近讀取的數據追加到 RequestData stringbuilder 對象中,
            // 該對象包含在 RequestState 中
            rs.RequestData.Append(str);


            // 現在發出另一個異步調用,讀取更多的數據
            // 請注意,將不斷調用此過程,直到
            // responseStream.EndRead 返回 -1
            IAsyncResult ar = responseStream.BeginRead(rs.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);
        }
        else
        {
            if (rs.RequestData.Length > 1)
            {
                // 所有數據都已被讀取,因此將其顯示到控制檯
                string strContent;
                strContent = rs.RequestData.ToString();
                Console.WriteLine(strContent);
            }

            // 關閉響應流
            responseStream.Close();

            // 設置 ManualResetEvent,以便主線程可以退出
            allDone.Set();
        }
        return;
    }
}

 

在這裏有回調函數,且異步回調中又有異步操作。

首先是異步獲得ResponseStream,然後異步讀取數據。

這個程序非常經典。從中可以學到很多東西的。我們來共同探討。

 

總結

上面說過,.net framework 可以異步調用任何方法。所以異步用處廣泛。

.net framework 類庫中也有很多異步調用的方法。一般都是已Begin開頭End結尾構成一對,異步委託方法,外加兩個回調函數和AsyncState參數,組成異步操作的宏觀體現。所以要做異步編程,不要忘了委託delegateBeginEndAsyncCallBack委託,AsyncState實例(在回調函數中通過IAsyncResult.AsyncState來強制轉換)IAsycResult(監控異步),就足以理解異步真諦了。

C#異步調用四大方法詳解:

http://developer.51cto.com/art/200908/145541.htm

C#異步調用四大方法是什麼呢?他們各自的作用是什麼呢?那麼本文就向你介紹C#異步調用四大方法的具體內容。

AD: 2013大數據全球技術峯會課程PPT下載

C#異步調用四大方法是什麼呢?C#異步調用四大方法的使用是如何進行的呢?讓我們首先了解下什麼時候用到C#異步調用:

.NET Framework 允許您C#異步調用任何方法。定義與您需要調用的方法具有相同簽名的委託;公共語言運行庫將自動爲該委託定義具有適當簽名的 BeginInvoke 和 EndInvoke 方法。

BeginInvoke 方法用於啓動C#異步調用。它與您需要異步執行的方法具有相同的參數,只不過還有兩個額外的參數(將在稍後描述)。BeginInvoke 立即返回,不等待C#異步調用完成。BeginInvoke 返回 IasyncResult,可用於監視調用進度。

EndInvoke 方法用於檢索C#異步調用結果。調用 BeginInvoke 後可隨時調用 EndInvoke 方法;如果C#異步調用未完成,EndInvoke 將一直阻塞到C#異步調用完成。EndInvoke 的參數包括您需要異步執行的方法的 out 和 ref 參數(在 Visual Basic 中爲 ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。

注意   Visual Studio .NET 中的智能感知功能會顯示 BeginInvoke 和 EndInvoke 的參數。如果您沒有使用 Visual Studio 或類似的工具,或者您使用的是 C# 和 Visual Studio .NET,請參見異步方法簽名獲取有關運行庫爲這些方法定義的參數的描述。

本主題中的代碼演示了四種使用 BeginInvoke 和 EndInvoke 進行C#異步調用的常用方法。調用了 BeginInvoke 後,可以:

· 進行某些操作,然後調用 EndInvoke 一直阻塞到調用完成。

· 使用 IAsyncResult.AsyncWaitHandle 獲取 WaitHandle,使用它的 WaitOne 方法將執行一直阻塞到發出 WaitHandle 信號,然後調用 EndInvoke。

· 輪詢由 BeginInvoke 返回的 IAsyncResult,確定C#異步調用何時完成,然後調用 EndInvoke。

· 將用於回調方法的委託傳遞給 BeginInvoke。該方法在C#異步調用完成後在 ThreadPool 線程上執行,它可以調用 EndInvoke。

警告:始終在C#異步調用完成後調用 EndInvoke。

測試方法和異步委託

四個示例全部使用同一個長期運行的測試方法 TestMethod。該方法顯示一個表明它已開始處理的控制檯信息,休眠幾秒鐘,然後結束。TestMethod 有一個 out 參數(在 Visual Basic 中爲 ByRef),它演示瞭如何將這些參數添加到 BeginInvoke 和 EndInvoke 的簽名中。您可以用類似的方式處理 ref 參數(在 Visual Basic 中爲 ByRef)。

下面的代碼示例顯示 TestMethod 以及代表 TestMethod 的委託;若要使用任一示例,請將示例代碼追加到這段代碼中。

注意   爲了簡化這些示例,TestMethod 在獨立於 Main() 的類中聲明。或者,TestMethod 可以是包含 Main() 的同一類中的 static 方法(在 Visual Basic 中爲 Shared)。

using System;  

using System.Threading;   

 

public class AsyncDemo {  

// The method to be executed asynchronously.  

//  

public string TestMethod(  

int callDuration, out int threadId) {  

Console.WriteLine("Test method begins.");  

10 Thread.Sleep(callDuration);  

11 threadId = AppDomain.GetCurrentThreadId();  

12 return "MyCallTime was " + callDuration.ToString();  

13 }  

14 }  

15  

16 // The delegate must have the same signature as the method  

17 // you want to call asynchronously.  

18 public delegate string AsyncDelegate(  

19 int callDuration, out int threadId);  

20    

21  

22 using System;  

23 using System.Threading;   

24  

25 public class AsyncDemo {  

26 // The method to be executed asynchronously.  

27 //  

28 public string TestMethod(  

29 int callDuration, out int threadId) {  

30 Console.WriteLine("Test method begins.");  

31 Thread.Sleep(callDuration);  

32 threadId = AppDomain.GetCurrentThreadId();  

33 return "MyCallTime was " + callDuration.ToString();  

34 }  

35 }  

36  

37 // The delegate must have the same signature as the method  

38 // you want to call asynchronously.  

39 public delegate string AsyncDelegate(  

40 int callDuration, out int threadId); 

C#異步調用四大方法之使用 EndInvoke 等待異步調用

異步執行方法的最簡單方式是以 BeginInvoke 開始,對主線程執行一些操作,然後調用 EndInvoke。EndInvoke 直到C#異步調用完成後才返回。這種技術非常適合文件或網絡操作,但是由於它阻塞 EndInvoke,所以不要從用戶界面的服務線程中使用它。

41 public class AsyncMain {  

42 static void Main(string[] args) {  

43 // The asynchronous method puts the thread id here.  

44 int threadId;  

45  

46 // Create an instance of the test class.  

47 AsyncDemo ad = new AsyncDemo();  

48  

49 // Create the delegate.  

50 AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);  

51      

52 // Initiate the asychronous call.  

53 IAsyncResult ar = dlgt.BeginInvoke(3000,   

54 out threadId, nullnull);  

55  

56 Thread.Sleep(0);  

57 Console.WriteLine("Main thread {0} does some work.",  

58 AppDomain.GetCurrentThreadId());  

59  

60 // Call EndInvoke to Wait for   

61 //the asynchronous call to complete,  

62 // and to retrieve the results.  

63 string ret = dlgt.EndInvoke(out threadId, ar);  

64  

65 Console.WriteLine("The call executed on thread {0},   

66 with return value \"{1}\".", threadId, ret);  

67 }  

68 

C#異步調用四大方法之使用 WaitHandle 等待異步調用

等待 WaitHandle 是一項常用的線程同步技術。您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 屬性來獲取 WaitHandle。C#異步調用完成時會發出 WaitHandle 信號,而您可以通過調用它的 WaitOne 等待它。

如果您使用 WaitHandle,則在C#異步調用完成之後,但在通過調用 EndInvoke 檢索結果之前,可以執行其他處理。

69 public class AsyncMain {  

70 static void Main(string[] args) {  

71 // The asynchronous method puts the thread id here.  

72 int threadId;  

73  

74 // Create an instance of the test class.  

75 AsyncDemo ad = new AsyncDemo();  

76  

77 // Create the delegate.  

78 AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);  

79      

80 // Initiate the asychronous call.  

81 IAsyncResult ar = dlgt.BeginInvoke(3000,   

82 out threadId, nullnull);  

83  

84 Thread.Sleep(0);  

85 Console.WriteLine("Main thread {0} does some work.",  

86 AppDomain.GetCurrentThreadId());  

87  

88 // Wait for the WaitHandle to become signaled.  

89 ar.AsyncWaitHandle.WaitOne();  

90  

91 // Perform additional processing here.  

92 // Call EndInvoke to retrieve the results.  

93 string ret = dlgt.EndInvoke(out threadId, ar);  

94  

95 Console.WriteLine("The call executed on thread {0},   

96 with return value \"{1}\".", threadId, ret);  

97 }  

98 

C#異步調用四大方法之輪詢異步調用完成

您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 屬性來發現C#異步調用何時完成。從用戶界面的服務線程中進行C#異步調用時可以執行此操作。輪詢完成允許用戶界面線程繼續處理用戶輸入。

99 public class AsyncMain {  

100 static void Main(string[] args) {  

101 // The asynchronous method puts the thread id here.  

102 int threadId;  

103  

104 // Create an instance of the test class.  

105 AsyncDemo ad = new AsyncDemo();  

106  

107 // Create the delegate.  

108 AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);  

109      

110 // Initiate the asychronous call.  

111 IAsyncResult ar = dlgt.BeginInvoke(3000,   

112 out threadId, nullnull);  

113  

114 // Poll while simulating work.  

115 while(ar.IsCompleted == false) {  

116 Thread.Sleep(10);  

117 }  

118  

119 // Call EndInvoke to retrieve the results.  

120 string ret = dlgt.EndInvoke(out threadId, ar);  

121  

122 Console.WriteLine("The call executed on thread {0},  

123  with return value \"{1}\".", threadId, ret);  

124 }  

125 

C#異步調用四大方法之異步調用完成時執行回調方法

如果啓動異步調用的線程不需要處理調用結果,則可以在調用完成時執行回調方法。回調方法在 ThreadPool 線程上執行。

要使用回調方法,必須將代表該方法的 AsyncCallback 委託傳遞給 BeginInvoke。也可以傳遞包含回調方法將要使用的信息的對象。例如,可以傳遞啓動調用時曾使用的委託,以便回調方法能夠調用 EndInvoke。

126 public class AsyncMain {  

127 // Asynchronous method puts the thread id here.  

128 private static int threadId;  

129  

130 static void Main(string[] args) {  

131 // Create an instance of the test class.  

132 AsyncDemo ad = new AsyncDemo();  

133  

134 // Create the delegate.  

135 AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);  

136      

137 // Initiate the asychronous call.  Include an AsyncCallback  

138 // delegate representing the callback method, and the data  

139 // needed to call EndInvoke.  

140 IAsyncResult ar = dlgt.BeginInvoke(3000,  

141 out threadId,   

142 new AsyncCallback(CallbackMethod),  

143 dlgt );  

144  

145 Console.WriteLine("Press Enter to close application.");  

146 Console.ReadLine();  

147 }  

148  

149 // Callback method must have the same signature as the  

150 // AsyncCallback delegate.  

151 static void CallbackMethod(IAsyncResult ar) {  

152 // Retrieve the delegate.  

153 AsyncDelegate dlgt = (AsyncDelegate) ar.AsyncState;  

154  

155 // Call EndInvoke to retrieve the results.  

156 string ret = dlgt.EndInvoke(out threadId, ar);  

157  

158 Console.WriteLine("The call executed on thread {0},  

159  with return value \"{1}\".", threadId, ret);  

160 }  

161 }  

C#異步調用四大方法的基本內容就向你介紹到這裏,希望對你瞭解和學習C#異步調用有所幫助。

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