說明:
.NET Compact Framework 中不支持異步委托調用,也就是 BeginInvoke 和 EndInvoke 方法。
BeginInvoke 方法啟動異步調用。該方法與您需要異步執行的方法具有相同的參數,還有另外兩個可選參數。第一個參數是一個 AsyncCallback 委托,該委托引用在異步調用完成時要調用的方法。第二個參數是一個用戶定義的對象,該對象將信息傳入回調方法。BeginInvoke 會立即返回,而不等待異步調用完成。BeginInvoke 返回一個可用于監視異步調用進度的 IAsyncResult。
EndInvoke 方法檢索異步調用的結果。在調用 BeginInvoke 之后隨時可以調用該方法。如果異步調用尚未完成,則 EndInvoke 會一直阻止調用線程,直到異步調用完成。EndInvoke 的參數包括您需要異步執行的方法的 out 和 ref 參數(在 Visual Basic 中為 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。
說明:
Visual Studio 2005 中的 IntelliSense 功能顯示 BeginInvoke 和 EndInvoke 的參數。如果您沒有使用 Visual Studio 或類似工具,或您使用的是帶有 Visual Studio 2005 的 C#,請參見 異步編程概述 以獲取為這些方法定義的參數的說明。
本主題中的代碼示例演示了使用 BeginInvoke 和 EndInvoke 進行異步調用的四種常用方法。調用 BeginInvoke 之后,您可以執行下列操作:
進行某些操作,然后調用 EndInvoke 一直阻止到調用完成。
使用 IAsyncResult.AsyncWaitHandle 屬性獲取 WaitHandle,使用其 WaitOne 方法一直阻止執行直到發出 WaitHandle 信號,然后調用 EndInvoke。
輪詢由 BeginInvoke 返回的 IAsyncResult,以確定異步調用何時完成,然后調用 EndInvoke。
將用于回調方法的委托傳遞給 BeginInvoke。異步調用完成后,將在 ThreadPool 線程上執行該方法?;卣{方法調用 EndInvoke。
重要說明:
無論您使用何種方法,都要調用 EndInvoke 來完成異步調用。
定義測試方法和異步委托
下面的代碼示例演示異步調用同一個長時間運行的方法 TestMethod 的各種方式。TestMethod 方法會顯示一條控制臺消息,說明該方法已開始處理,休眠了幾秒鐘,然后結束。TestMethod 有一個 out 參數,該參數用于演示此種參數添加到 BeginInvoke 和 EndInvoke 的簽名中的方式。您可以按同樣的方式處理 ref 參數。
下面的代碼示例演示 TestMethod 的定義和名為 AsyncMethodCaller 的、可用來異步調用 TestMethod 的委托。若要編譯代碼示例,必須包括 TestMethod 的定義和 AsyncMethodCaller 委托。
C#
異步執行方法的最簡單方式是通過調用委托的 BeginInvoke 方法來開始執行方法,在主線程上執行一些操作,然后調用委托的 EndInvoke 方法。EndInvoke 可能會阻止調用線程,因為該方法直到異步調用完成后才返回。這種方式非常適合執行文件或網絡操作。
重要說明:
因為 EndInvoke 可能會阻塞,所以不應從服務于用戶界面的線程調用該方法。
C#
//通過委托調用方法,回調函數為null
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine("Main thread {0} does some work.",
Thread.CurrentThread.ManagedThreadId);
// Call EndInvoke to wait for the asynchronous call to complete,會阻塞
// and to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("The call executed on thread {0}, with return value /"{1}/".",
threadId, returnValue);
}
}
}
您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 屬性來獲取 WaitHandle。異步調用完成時會發出 WaitHandle 信號,而您可以通過調用 WaitOne 方法等待它。
如果您使用 WaitHandle,則在異步調用完成之前或之后,但在通過調用 EndInvoke 檢索結果之前,還可以執行其他處理。
說明:
調用 EndInvoke 時不會自動關閉等待句柄。如果釋放對等待句柄的所有引用,則當垃圾回收功能回收等待句柄時,將釋放系統資源。若要在等待句柄使用完畢后立即釋放系統資源,請調用 WaitHandle.Close 方法來釋放等待句柄。顯式釋放可釋放的對象時,垃圾回收的工作效率會更高。
C#
//定義委托.
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);
// Wait for the WaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
// Perform additional processing here.
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
// Close the wait handle.
result.AsyncWaitHandle.Close();
Console.WriteLine("The call executed on thread {0}, with return value /"{1}/".",
threadId, returnValue);
}
}
}
輪詢異步調用完成
您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 屬性來發現異步調用何時完成。從用戶界面的服務線程中進行異步調用時可以執行此操作。輪詢完成允許調用線程在異步調用在 ThreadPool 線程上執行時繼續執行。
C#C++VB
//實例化.
AsyncDemo ad = new AsyncDemo();
//聲明委托
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
//調用.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
//輪詢.
while(result.IsCompleted == false) {
Thread.Sleep(250);
Console.Write(".");
}
//取結果.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("/nThe call executed on thread {0}, with return value /"{1}/".",
threadId, returnValue);
}
}
}
異步調用完成時執行回調方法
如果啟動異步調用的線程不需要是處理結果的線程,則可以在調用完成時執行回調方法?;卣{方法在 ThreadPool 線程上執行。
若要使用回調方法,必須將表示回調方法的 AsyncCallback 委托傳遞給 BeginInvoke。也可以傳遞包含回調方法要使用的信息的對象。在回調方法中,可以將 IAsyncResult(回調方法的唯一參數)強制轉換為 AsyncResult 對象。然后,可以使用 AsyncResult.AsyncDelegate 屬性獲取已用于啟動調用的委托,以便可以調用 EndInvoke。
有關示例的說明:
TestMethod 的 threadId 參數為 out 參數(在 Visual Basic 中為 <Out> ByRef),因此 TestMethod 從不使用該參數的輸入值。會將一個虛擬變量傳遞給 BeginInvoke 調用。如果 threadId 參數為 ref 參數(在 Visual Basic 中為 ByRef),則該變量必須為類級別字段,這樣才能同時傳遞給 BeginInvoke 和 EndInvoke。
傳遞給 BeginInvoke 的狀態信息是一個格式字符串,回調方法使用該字符串來設置輸出消息的格式。因為作為類型 Object 進行傳遞,所以狀態信息必須強制轉換為正確的類型才能被使用。
回調是在 ThreadPool 線程上進行的。ThreadPool 線程是后臺線程,這些線程不會在主線程結束后保持應用程序的運行,因此示例的主線程必須休眠足夠長的時間以便回調完成。
C#
//實例兩個不同的委托,分別對應不同的方法.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
AsyncMethodCaller2 caller2 = new AsyncMethodCaller2(ad.Addxy);
// The threadId parameter of TestMethod is an out parameter, so
// its input value is never used by TestMethod. Therefore, a dummy
// variable can be passed to the BeginInvoke call. If the threadId
// parameter were a ref parameter, it would have to be a class-
// level field so that it could be passed to both BeginInvoke and
// EndInvoke.
int dummy = 0;
// 調用時指定回調方法,在異步執行完后會自動調用該方法,用來取得執行的結果
IAsyncResult result = caller.BeginInvoke(3000,
out dummy,
new AsyncCallback(CallbackMethod),
"The call executed on thread {0}, with return value /"{1}/".");
caller2.BeginInvoke(2, 3, CallbackMethod2, "this is add");
Console.WriteLine("The main thread {0} continues to execute...",
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(4000);
Console.WriteLine("The main thread ends.");
}
// The callback method must have the same signature as the
// AsyncCallback delegate.
private void CallbackMethod(IAsyncResult ar)
{
// Retrieve the delegate.
AsyncResult result = (AsyncResult) ar;
//強制轉換成對應的委托對象
AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;
// Retrieve the format string that was passed as state
// information.
string formatString = (string) ar.AsyncState;
// Define a variable to receive the value of the out parameter.
// If the parameter were ref rather than out then it would have to
// be a class-level field so it could also be passed to BeginInvoke.
int threadId = 0;
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, ar);
// Use the format string to format the output message.
Console.WriteLine(formatString, threadId, returnValue);
}
private void CallbackMethod2(IAsyncResult ar)
{
// Retrieve the delegate.
AsyncResult result = (AsyncResult)ar;
//強制轉換成對應的委托對象
AsyncMethodCaller2 caller = (AsyncMethodCaller2)result.AsyncDelegate;
// 取得狀態
string formatString = (string)ar.AsyncState;
//調用異步完成的方法,取得執行結果
string returnValue = caller.EndInvoke(ar).ToString();
//此種方式是在windows應用程序給控件賦值時用,因為在非創建線程不能操作控件
this.Invoke(new Action<string>((u) => tb_datainfo.Text += u), returnValue);
//tb_datainfo.Text = caller.EndInvoke(out threadId, ar);
// Use the format string to format the output message.
//Console.WriteLine(formatString, threadId, returnValue);
}
}
}
}
新聞熱點
疑難解答