異步調用詳解

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

.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,請參見異步方法簽名獲取有關運行庫爲這些方法定義的參數的描述。
一.C#異步調用四大方法詳解app

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

· 進行某些操做,而後調用 EndInvoke
一直阻塞到調用完成。
async

· 使用
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.");
        Thread.Sleep(callDuration);
        threadId = AppDomain.GetCurrentThreadId();
        return "MyCallTime was" + callDuration.ToString();
     }
}
// The delegate must have
//the same signature as the method
// you want to call asynchronously.
public delegate string AsyncDelegate(int callDuration, out int threadId);

 

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

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

public class AsyncMain
{
    static void Main(string[] args)
    {
        // The asynchronous method
      //  puts the thread id here.
    int threadId;
AsyncDemo ad = new AsyncDemo();

AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);

    IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null, null);
    Thread.Sleep(0);
Console.WriteLine("Main thread{0} does some work.",
AppDomain.GetCurrentThreadId());

string ret = dlgt.EndInvoke(out threadId, ar);
    Console.WriteLine("The call executed on thread{0},with return value\"{1}\".",threadId, ret);
}
}

 

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

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

若是您使用 WaitHandle,則在C#異步調用完成以後,但在經過調用 EndInvoke
檢索結果以前,能夠執行其餘處理。

public class AsyncMain
{
    static void Main(string[] args)
    {
    int threadId;
    AsyncDemo ad = new AsyncDemo();
    AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);
    IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null,null);
    Thread.Sleep(0);
    Console.WriteLine("Main thread{0} does some work.",AppDomain.GetCurrentThreadId());
    string ret = dlgt.EndInvoke(out threadId, ar);
    Console.WriteLine("The call executed on thread{0},with return value\"{1}\".",threadId, ret);
    }
}

 

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

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

public class AsyncMain
{
    static void Main(string[] args)
    {
      int threadId;
  
       AsyncDemo ad = new AsyncDemo();

       AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);

       IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null,null);

        while(ar.IsCompleted ==false) {
          Thread.Sleep(10);
        }

        string ret = dlgt.EndInvoke(out threadId, ar);
        Console.WriteLine("The call executed on thread{0},with return value\"{1}\".",threadId, ret);
    }
}

 

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

若是啓動異步調用的線程不須要處理調用結果,則能夠在調用完成時執行回調方法。回調方法在
ThreadPool 線程上執行。

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

public class AsyncMain
{

   private static int threadId;
   static void Main(string[] args)
    {

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

    IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId,new AsyncCallback(CallbackMethod),dlgt);
    Console.WriteLine("DIVss Enter to close application.");
    Console.ReadLine();
    }
  static void CallbackMethod(IAsyncResult ar)
 {

   AsyncDelegate dlgt = (AsyncDelegate)

   string ret = dlgt.EndInvoke(out threadId, ar);
    Console.WriteLine("The call executed on thread{ 0},with return value\"{1}\".",threadId, ret);
 }
}

 

 

二.C#異步調用四大方法的基本內容就向你介紹到這裏,下面看有回調函數的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);

       allDone.WaitOne();
    }

    public static void showusage()
    {
        Console.WriteLine("嘗試獲取 (GET) 一個 URL");
        Console.WriteLine("\r\n用法::");
        Console.WriteLine("ClientGetAsync URL");
        Console.WriteLine("示例::");
        Console.WriteLine("ClientGetAsyn  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參數,組成異步操做的宏觀體現。因此要作異步編程,不要忘了委託delegate、Begin,End,AsyncCallBack委託,AsyncState實例(在回調函數中經過IAsyncResult.AsyncState來強制轉換),IAsycResult(監控異步),就足以理解異步真諦了

 

資源來自網絡,分別爲:

http://www.cnblogs.com/ericwen/archive/2008/03/12/1101801.html

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

相關文章
相關標籤/搜索