程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#基礎學習 —— 異步編程篇 (一)

C#基礎學習 —— 異步編程篇 (一)

編輯:關於C#

.NET Framework 為異步操作提供了兩種設計模式:使用 IAsyncResult 對象的異步操作與使用事件的異步操作。先來學習前者

概述

IAsyncResult 異步設計模式通過名為 BeginOperationName 和 EndOperationName 的兩個方法來實現原同步方法的異步調用,如 FileStream 類提供了 BeginRead 和 EndRead 方法來從文件異步讀取字節,它們是 Read 方法的異步版本

Begin 方法包含同步方法簽名中的任何參數,此外還包含另外兩個參數:一個AsyncCallback 委托和一個用戶定義的狀態對象。委托用來調用回調方法,狀態對象是用來向回調方法傳遞狀態信息。該方法返回一個實現 IAsyncResult 接口的對象

End 方法用於結束異步操作並返回結果,因此包含同步方法簽名中的 ref 和 out 參數,返回值類型也與同步方法相同。該方法還包括一個 IAsyncResult 參數,用於獲取異步操作是否完成的信息,當然在使用時就必須傳入對應的 Begin 方法返回的對象實例

開始異步操作後如果要阻止應用程序,可以直接調用 End 方法,這會阻止應用程序直到異步操作完成後再繼續執行。也可以使用 IAsyncResult的 AsyncWaitHandle屬性,調用其中的WaitOne等方法來阻塞線程。這兩種方法的區別不大,只是前者必須一直等待而後者可以設置等待超時

如果不阻止應用程序,則可以通過輪循 IAsyncResult的 IsCompleted狀態來判斷操作是否完成,或使用 AsyncCallback 委托來結束異步操作。AsyncCallback 委托包含一個 IAsyncResult的簽名,回調方法內部再調用 End 方法來獲取操作執行結果

嘗試

先來熟悉一下今天的主角,IAsyncResult 接口

public interface IAsyncResult
  {
    object AsyncState { get; }
    WaitHandle AsyncWaitHandle { get; }
    bool CompletedSynchronously { get; }
    bool IsCompleted { get; }
  }

我用一個 AsyncDemo 類作為異步方法的提供者,後面的程序都會調用它。內部很簡單,構造函數接收一個字符串作為 name ,Run 方法輸出 "My name is " + name ,而異步方法直接用委托的 BeginInvoke 和 EndInvoke 方法實現

public class AsyncDemo
  {
    // Use in asynchronous methods
    private delegate string runDelegate();
    private string m_Name;
    private runDelegate m_Delegate;
    public AsyncDemo(string name)
    {
      m_Name = name;
      m_Delegate = new runDelegate(Run);
    }
    /**//// <summary>
    /// Synchronous method
    /// </summary>
    /// <returns></returns>
    public string Run()
    {
      return "My name is " + m_Name;
    }
    /**//// <summary>
    /// Asynchronous begin method
    /// </summary>
    /// <param name="callBack"></param>
    /// <param name="stateObject"></param>
    /// <returns></returns>
    public IAsyncResult BeginRun(AsyncCallback callBack, Object stateObject)
    {
      try
      {
        return m_Delegate.BeginInvoke(callBack, stateObject);
      }
      catch(Exception e)
      {
        // Hide inside method invoking stack
        throw e;
      }
    }
    /**//// <summary>
    /// Asynchronous end method
    /// </summary>
    /// <param name="ar"></param>
    /// <returns></returns>
    public string EndRun(IAsyncResult ar)
    {
      if (ar == null)
        throw new NullReferenceException("Arggument ar can't be null");
      try
      {
        return m_Delegate.EndInvoke(ar);
      }
      catch (Exception e)
      {
        // Hide inside method invoking stack
        throw e;
      }
    }
  }

首先是 Begin 之後直接調用 End 方法,當然中間也可以做其他的操作

class AsyncTest
  {
    static void Main(string[] args)
    {
      AsyncDemo demo = new AsyncDemo("jiangnii");
      // Execute begin method
      IAsyncResult ar = demo.BeginRun(null, null);
      // You can do other things here
      // Use end method to block thread until the operation is complete
      string demoName = demo.EndRun(ar);
      Console.WriteLine(demoName);
    }
  }

也可以用 IAsyncResult的 AsyncWaitHandle屬性,我在這裡設置為1秒超時

class AsyncTest
  {
    static void Main(string[] args)
    {
      AsyncDemo demo = new AsyncDemo("jiangnii");
      // Execute begin method
      IAsyncResult ar = demo.BeginRun(null, null);
      // You can do other things here
      // Use AsyncWaitHandle.WaitOne method to block thread for 1 second at most
      ar.AsyncWaitHandle.WaitOne(1000, false);
      if (ar.IsCompleted)
      {
        // Still need use end method to get result, but this time it will return immediately
        string demoName = demo.EndRun(ar);
        Console.WriteLine(demoName);
      }
      else
      {
        Console.WriteLine("Sorry, can't get demoName, the time is over");
      }
    }
  }

不中斷的輪循,每次循環輸出一個 "."

class AsyncTest
  {
    static void Main(string[] args)
    {
      AsyncDemo demo = new AsyncDemo("jiangnii");
      // Execute begin method
      IAsyncResult ar = demo.BeginRun(null, null);
      Console.Write("Waiting..");
      while (!ar.IsCompleted)
      {
        Console.Write(".");
        // You can do other things here
      }
      Console.WriteLine();
      // Still need use end method to get result, but this time it will return immediately
      string demoName = demo.EndRun(ar);
      Console.WriteLine(demoName);
    }
  }

最後是使用回調方法並加上狀態對象,狀態對象被作為 IAsyncResult 參數的AsyncState 屬性被傳給回調方法。回調方法執行前不能讓主線程退出,我這裡只是簡單的讓其休眠了1秒。另一個與之前不同的地方是 AsyncDemo對象被定義成了類的靜態字段,以便回調方法使用

class AsyncTest
  {
    static AsyncDemo demo = new AsyncDemo("jiangnii");
    static void Main(string[] args)
    {
      // State object
      bool state = false;
      // Execute begin method
      IAsyncResult ar = demo.BeginRun(new AsyncCallback(outPut), state);
      // You can do other thins here
      // Wait until callback finished
      System.Threading.Thread.Sleep(1000);
    }
    // Callback method
    static void outPut(IAsyncResult ar)
    {
      bool state = (bool)ar.AsyncState;
      string demoName = demo.EndRun(ar);
      if (state)
      {
        Console.WriteLine(demoName);
      }
      else
      {
        Console.WriteLine(demoName + ", isn't it?");
      }
    }
  }

其他

對於一個已經實現了 BeginOperationName 和 EndOperationName 方法的對象,我們可以直接用上述方式調用,但對於只有同步方法的對象,我們要對其進行異步調用也不需要增加對應的異步方法,而只需定義一個委托並使用其 BeginInvoke 和 EndInvoke 方法就可以了

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved