基於委託的異步編程實現

神麼是異步調用

在主線程中異步調用的方法不在主線程中執行,而是在另外一個輔助線程中與主線程代碼並行執行。給出一段示例代碼:異步

當咱們調用UploadPictureAsync方法時,圖片還沒有上傳完成,咱們就能夠在控制檯輸出提示信息:「圖片開始上傳」。async

/// <summary> /// 異步上傳圖片 /// </summary> /// <param name="fileLocalPath"></param> public void UploadPictureAsync(string id, string fileLocalPath) { DelegateMgr.UploadFileHandler del = new DelegateMgr.UploadFileHandler(UploadFile); del.BeginInvoke(id, fileLocalPath, delegate(IAsyncResult ar) { try { string fileUri = del.EndInvoke(ar); FileUploadEventArgs args = new FileUploadEventArgs(id, fileUri); if (PictureUploadCompleted != null) { PictureUploadCompleted(args); } } catch (Exception ex) { LogUtility.LogTableMessage("圖片上傳異常," + ex); } }, null);spa

Console.WriteLine("圖片開始上傳" ); } private string UploadFile(string id, string filePath) { string fileUri = string.Empty; try { WebClient wc = new WebClient(); string targetPath = "http://172.16.50.179:8090/FileUpload/ImageUpLoad.do"; byte[] bytes = wc.UploadFile(targetPath, "POST", filePath); fileUri = Encoding.Default.GetString(bytes);線程

Console.WriteLine("圖片完成上傳" ); } catch (Exception exception) { LogUtility.LogTableMessage("上傳圖片異常," + exception); } return fileUri; } public event Action<FileUploadEventArgs> PictureUploadCompleted;code

編譯器對委託都作了些神麼。。。

當咱們定義一個委託時,編譯器會爲委託生成一個類。好比咱們定義以下委託:對象

public delegate int DemoDelegate(int a, int b);

編譯器會生成以下格式的類:blog

public sealed class DemoDelegate : MulticastDelegate
    {
        public DemoDelegate(object @object, IntPtr method)
        {
            //
        }

        public virtual int Invoke(int a, int b)
        {
            //方法體爲空
        }

        public virtual IAsyncResult BeginInvoke(int a, int b, AsyncCallback callback, object asyncState)
        {
            //方法體爲空
        }

        public virtual int EndInvoke(IAsyncResult ar)
        {
            //方法體爲空
        }
    }
請注意,上面3個方法都是虛方法virtual,而且方法體都爲空。

同步調用實現

class Program
    {
        static void Main(string[] args)
        {

            DemoDelegate del = new DemoDelegate(Add);

            //同步調用   Console.WriteLine("1 + 2 = " +  del(1, 2));

        }

        static int Add(int a, int b)
        {
            return a + b;
        }
    }

上面這種同步調用方式,實際上調用的是委託類的 Invoke 方法。接口

異步調用實現

基於委託的異步調用,其實是經過 BeginInvoke 和 EndInvoke 兩個方法來實現的。圖片

咱們先來分析一下BeginInvoke方法get

public IAsyncResult BeginInvoke(

    <輸入和輸出變量>,

    AsyncCallback callback, object asyncState

)

<輸入和輸出變量>,表示委託聲明中,參數有ref或者out修飾的。

callback,異步調用結束時自動回調的方法

asyncState,用於向callback方法提供參數信息,好比回調方法須要一些參數,asyncState 就能夠用於填充這些參數。

對BeginInvoke方法的返回類型 IAsyncResult接口的說明

    [ComVisible(true)]
    public interface IAsyncResult
    {       
        object AsyncState { get; }
        WaitHandle AsyncWaitHandle { get; }
        bool CompletedSynchronously { get; }
        bool IsCompleted { get; }
    }

AsyncState,直接存儲BeginInvoke方法中傳入的 asyncState 參數值

AsyncWaitHandle,當異步操做完成時,該句柄處於 signaled 狀態。

CompletedSynchronously,表示BeginInvoke是否同步調用完成。

IsCompleted,能夠經過循環查詢該屬性判斷異步操做是否完成。

 

接下來咱們分析一下 EndInvoke 方法

public <方法返回值類型> EndInvoke(

    <聲明爲ref或out的參數>,

    IAsyncResult result)

調用 BeginInvoke方法會返回一個類型爲 IAsyncResult 的對象,該對象會做爲 EndInvoke方法的參數,這樣EndInvoke方法不斷輪詢異步執行結果,發現異步調用完成時,會將異步調用結果做爲返回值,若是異步調用方法有 ref 或者 out參數,也會負責填充這些參數。

調用者線程                         輔助線程

    |

    ①BeginInvoke     ------------------------>                          

    |                             ②異步調用方法執行

    ③EndInvoke      <-------------------------                         

相關文章
相關標籤/搜索