當我們的程序順序執行的時候,如果我們調用了一個很耗時的方法,那麼應用程序會使當前的線程處於阻塞狀態,直到方法的調用完成再繼續執行。這樣的方法調用被認爲是同步的。如果我們調用了一個遠程的方法,那麼這個方法的調用可能花費的時間會更長。如果我們不想立即取得方法所返回的結果,或者我們根本就不讓方法返回結果的話,這種等待是沒有必要的。
如果我們想調用一個這樣的方法,當調用之後就立即返回,假如在調用期間發生了異常,我們可以在稍後的時間重起該方法的動作。那我們就可以利用異步委託來把我們的方法做成異步的調用。
每個委託都有三個方法:Invoke、BeginInvoke、EndInvoke。
第一個方法是委託指定函數的同步調用,另外兩個是異步調用。
如果我們自己寫了個委託
public delegate string MyDelegate(string name);
那麼C#就會自動爲我們提供了下面兩個方法:
IAsyncResult BeginInvoke(string name,AsyncResult callback,Object o)
以及
string EndInvoke(IAsyncResult result);
以上內容摘自http://www.cnblogs.com/wenwuxianren/archive/2008/04/17/1158504.html和
http://www.cnblogs.com/everx/archive/2007/02/01/519218.html
下面是MSDN上的官方解釋
異步委託提供以異步方式調用同步方法的能力。當同步調用一個委託時,“Invoke”方法直接對當前線程調用目標方法。如果編譯器支持異步委託,則它將生成“Invoke”方法以及“BeginInvoke”和“EndInvoke”方法。如果調用“BeginInvoke”方法,則公共語言運行庫 (CLR) 將對請求進行排隊並立即返回到調用方。將對來自線程池的線程調用該目標方法。提交請求的原始線程自由地繼續與目標方法並行執行,該目標方法是對線程池線程運行的。如果在對“BeginInvoke”方法的調用中指定了回調方法,則當目標方法返回時將調用該回調方法。在回調方法中,“EndInvoke”方法獲取返回值和所有輸入/輸出參數。如果在調用“BeginInvoke”時未指定任何回調方法,則可以從調用“BeginInvoke”的線程中調用“EndInvoke”。
.NET Framework 允許您異步調用任何方法。爲此,應定義與您要調用的方法具有相同簽名的委託;公共語言運行庫會自動使用適當的簽名爲該委託定義 BeginInvoke 和 EndInvoke 方法。
BeginInvoke 方法可啓動異步調用。它與您需要異步執行的方法具有相同的參數,另外它還有兩個可選參數。第一個參數是一個 AsyncCallback 委託,該委託引用在異步調用完成時要調用的方法。第二個參數是一個用戶定義的對象,該對象可向回調方法傳遞信息。BeginInvoke 立即返回,不等待異步調用完成。BeginInvoke 會返回 IAsyncResult,這個結果可用於監視異步調用進度。
EndInvoke 方法檢索異步調用的結果。調用 BeginInvoke 後可隨時調用 EndInvoke 方法;如果異步調用尚未完成,EndInvoke 將一直阻止調用線程,直到異步調用完成後才允許調用線程執行。EndInvoke 的參數包括您需要異步執行的方法的 out 和 ref 參數(在 Visual Basic 中爲 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。
接下來,MSDN提供了兩個例子:
第一個例子是:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace AsyncDemo
{
class Program
{
public class AsyncDemo
{
// 這個方法將被異步調用
public string TestMethod(int callDuration, out int threadId)
{
Console.WriteLine("Test method begins.");
Thread.Sleep(callDuration);
threadId = Thread.CurrentThread.ManagedThreadId;
return String.Format("My call time was {0}.", callDuration.ToString());
}
}
// 異步調用方法的委託,這個委託必須與TestMethod有同樣的簽名
public delegate string AsyncMethodCaller(int callDuration, out int threadId);
public static void Main()
{
// 異步調用方法將把它的thread id放在這裏
int threadId;
// 構建一個測試實例
AsyncDemo ad = new AsyncDemo();
// 構建委託
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// 開始執行異步委託
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine("Main thread {0} does some work.",
Thread.CurrentThread.ManagedThreadId);
// EndInvoke一直阻塞,一直到異步調用完成之後才返回
// 並且取到了異步調用的返回值
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
}
第二個例子是:
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
using System.Collections.Generic;
using System.Text;
namespace DelegationTest
{
// 構造一個異步調用方法來分解因式
class PrimeFactorFinder
{
public static bool Factorize(
int number,
ref int primefactor1,
ref int primefactor2)
{
primefactor1 = 1;
primefactor2 = number;
// Factorize using a low-tech approach.
for (int i = 2; i < number; i++)
{
if (0 == (number % i))
{
primefactor1 = i;
primefactor2 = number / i;
break;
}
}
if (1 == primefactor1)
return false;
else
return true;
}
}
// 構建一個異步委託來匹配異步調用方法
public delegate bool AsyncFactorCaller(
int number,
ref int primefactor1,
ref int primefactor2);
public class DemonstrateAsyncPattern
{
// The waiter object used to keep the main application thread
// from terminating before the callback method completes.
ManualResetEvent waiter;
// Define the method that receives a callback when the results are available.
public void FactorizedResults(IAsyncResult result)
{
int factor1 = 0;
int factor2 = 0;
// Extract the delegate from the
// System.Runtime.Remoting.Messaging.AsyncResult.
AsyncFactorCaller factorDelegate = (AsyncFactorCaller)((AsyncResult)result).AsyncDelegate;
int number = (int)result.AsyncState;
// Obtain the result.
bool answer = factorDelegate.EndInvoke(ref factor1, ref factor2, result);
// Output the results.
Console.WriteLine("On CallBack: Factors of {0} : {1} {2} - {3}",
number, factor1, factor2, answer);
waiter.Set();
}
// 下面的方法演示了在異步調用中利用回調函數的方法(異步調用執行完成之後執行回調方法)
public void FactorizeNumberUsingCallback()
{
AsyncFactorCaller factorDelegate = new AsyncFactorCaller(PrimeFactorFinder.Factorize);
int number = 1000589023;
int temp = 0;
// Waiter will keep the main application thread from
// ending before the callback completes because
// the main thread blocks until the waiter is signaled
// in the callback.
waiter = new ManualResetEvent(false);
// Define the AsyncCallback delegate.
AsyncCallback callBack = new AsyncCallback(this.FactorizedResults);
// Asynchronously invoke the Factorize method.
IAsyncResult result = factorDelegate.BeginInvoke(
number,
ref temp,
ref temp,
callBack,
number);
// Do some other useful work while
// waiting for the asynchronous operation to complete.
// When no more work can be done, wait.
waiter.WaitOne();
}
// 下面的方法演示了異步調用時使用輪詢方法而非回調方法(會比回調方法效率低一些)
public void FactorizeNumberAndWait()
{
AsyncFactorCaller factorDelegate = new AsyncFactorCaller(PrimeFactorFinder.Factorize);
int number = 1000589023;
int temp = 0;
// Asynchronously invoke the Factorize method.
IAsyncResult result = factorDelegate.BeginInvoke(
number,
ref temp,
ref temp,
null,
null);
while (!result.IsCompleted)
{
// Do any work you can do before waiting.
result.AsyncWaitHandle.WaitOne(10000, false);
}
// The asynchronous operation has completed.
int factor1 = 0;
int factor2 = 0;
// Obtain the result.
bool answer = factorDelegate.EndInvoke(ref factor1, ref factor2, result);
// Output the results.
Console.WriteLine("Sequential : Factors of {0} : {1} {2} - {3}",
number, factor1, factor2, answer);
}
public static void Main()
{
DemonstrateAsyncPattern demonstrator = new DemonstrateAsyncPattern();
demonstrator.FactorizeNumberUsingCallback();
demonstrator.FactorizeNumberAndWait();
}
}
}