非同步方法呼叫
當一個線程調用方法後,直到方法執行完畢,線程才繼續執行,這種方法被稱為同步方法。然而,有些方法執行時間可能非常長,比如串口操作或訪問網路,這樣線程被阻塞,而無法響應使用者的其他請求。這種情況通常是無法忍受的,所以這時我們應該使用非同步方法呼叫。
非同步方法呼叫的原理是,在方法調用前為非同步方法呼叫指定一個回呼函數,方法調用後被線程池中的一個線程接管,執行該方法。主線程立即返回,繼續執行其他工作或響應使用者請求。如果非同步方法呼叫執行完畢,回呼函數被自動執行,以處理非同步方法呼叫的調用結果。
如何?非同步方法呼叫呢?C#通過非同步委託調用BeginInvoke和EndInvoke方法來實現非同步方法呼叫。
BeginInvoke方法原型:
IAsyncResult BeginInvoke(......, AsyncCallback callback, object o);
......表示非同步委託中定義的參數列表。
AsyncCallback參數是一個用於回呼函數的委託,它的原型為:
public delegate void AsyncCallback(IAsyncResult ar)。其中IAsyncResult參數用於封裝非同步方法呼叫的執行結果。
Object參數用於在主線程與回呼函數間傳遞一些附加資訊,如同步資訊。
EndInvoke方法原型:
xxx EndInvoke(IAsyncResult result);
xxx表示非同步委託原型中定義的返回資料類型,IAsyncResult用於封裝非同步方法呼叫的執行結果。
這麼看著是不是有點迷糊?看個例子就明白了:
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
namespace ProcessTest
{
class Program
{
//非同步呼叫執行完成同步訊號
static AutoResetEvent ev = new AutoResetEvent(false);
//定義委託
public delegate int Deleg(int a, int b);
static int WriteSum(int a, int b)
{
//顯示當前線程ID號及Sum值
Console.WriteLine("執行WriteSum的線程ID為:{0},Sum = {1}", Thread.CurrentThread.ManagedThreadId, a + b);
return a + b;
}
//回呼函數
static void SumDone(IAsyncResult async)
{
//等待1秒,類比線程正在執行其他工作
Thread.Sleep(1000);
//async中封裝了非同步方法呼叫執行的結果
//從操作結果async中還原委託
Deleg proc = ((AsyncResult)async).AsyncDelegate as Deleg;
//擷取非同步方法呼叫的執行結果
int sum = proc.EndInvoke(async);
//顯示結果
Console.WriteLine("執行SumDone的線程ID為:{0},Sum = {1}", Thread.CurrentThread.ManagedThreadId, sum);
//使用AsnycState屬性擷取主線程中傳入的同步訊號
//釋放同步訊號表示非同步呼叫已完成
((AutoResetEvent)async.AsyncState).Set();
}
static void Main(string[] args)
{
//建立一個委託
Deleg proc = new Deleg(WriteSum);
//採用非同步方式調用委託
//指定SumDone為非同步作業完成後的回呼函數
//指定ev為object參數,用於同步回呼函數與主線程間操作
IAsyncResult async = proc.BeginInvoke(10, 10, SumDone, ev);
Console.WriteLine("主線程ID號為:{0},非同步作業已開始執行,正等待操作完成。", Thread.CurrentThread.ManagedThreadId);
//等待非同步作業完成
ev.WaitOne();
Console.WriteLine("非同步作業已完成!");
System.Console.ReadKey();
}
}
}
是程式的運行結果:
注意觀察運行結果,非同步方法呼叫和回呼函數是在同一步線程執行。
為方法指定OneWay特性
我們可將System.Runtime.Remoting.Messaging.OneWay特性應用於任何一個方法,該特性告訴CLR該方法不返回任何資訊。即使該方法實際返回了資料(通過return語句或out、ref定義的參數),但只要被標記了OneWay特性,那它就不會再返回任何資訊。
一個被標記為OneWay特性的方法即可以同步方式調用,也可以非同步方式調用。如果在它的執行過程中引起了一個異常卻沒有捕獲,在同步方式下,該異常會向上傳播;但在非同步方式下,該異常將不會被傳播。大多數情況下,被標記為OneWay的方法是以非同步方式工作。