使用異步方式調用同步方法

(查詢BeginInvoke 2005MSDN 裏相關資料,我複製在這裏)

 

.NET Framework 允許您異步調用任何方法。爲此,應定義與您要調用的方法具有相同簽名的委託;公共語言運行庫會自動使用適當的簽名爲該委託定義 BeginInvoke 和 EndInvoke 方法。

BeginInvoke 方法可啓動異步調用。它與您需要異步執行的方法具有相同的參數,另外它還有兩個可選參數。第一個參數是一個 AsyncCallback 委託,該委託引用在異步調用完成時要調用的方法。第二個參數是一個用戶定義的對象,該對象可向回調方法傳遞信息。BeginInvoke 立即返回,不等待異步調用完成。BeginInvoke 會返回 IAsyncResult,這個結果可用於監視異步調用進度。

EndInvoke 方法檢索異步調用的結果。調用 BeginInvoke 後可隨時調用 EndInvoke 方法;如果異步調用尚未完成,EndInvoke 將一直阻止調用線程,直到異步調用完成後才允許調用線程執行。EndInvoke 的參數包括您需要異步執行的方法的 out 和 ref 參數(在 Visual Basic 中爲 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。

 

本主題中的代碼示例演示了四種使用 BeginInvoke 和 EndInvoke 進行異步調用的常用方法。調用 BeginInvoke 之後,您可以執行下列操作:

  • 進行某些操作,然後調用 EndInvoke 一直阻止到調用完成。

  • 使用 System.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 委託。

I
C# 
using System;
using System.Threading; 

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncDemo 
    {
        // The method to be executed asynchronously.
        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());
        }
    }
    // The delegate must have the same signature as the method
    // it will call asynchronously.
    public delegate string AsyncMethodCaller(int callDuration, out int threadId);
}

使用 EndInvoke 等待異步調用

異步執行方法最簡單的方式是通過調用委託的 BeginInvoke 方法來開始執行方法,在主線程上執行一些工作,然後調用委託的 EndInvoke 方法。EndInvoke 可能會阻止調用線程,因爲它直到異步調用完成之後才返回。這種技術非常適合文件或網絡操作,但是由於 EndInvoke 會阻止它,所以不要從服務於用戶界面的線程中調用它。

C# 
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        public static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            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);
        }
    }
}

使用 WaitHandle 等待異步調用

您可以使用 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 屬性來獲取 WaitHandle。異步調用完成時會發出 WaitHandle 信號,而您可以通過調用 WaitOne 方法等待它。

如果您使用 WaitHandle,則在異步調用完成之前或之後,在通過調用 EndInvoke 檢索結果之前,還可以執行其他處理。

C# 
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() 
        {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            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);

            Console.WriteLine("The call executed on thread {0}, with return value /"{1}/".",
                threadId, returnValue);
        }
    }
}

輪詢異步調用完成

您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 屬性來發現異步調用何時完成。從用戶界面的服務線程中進行異步調用時可以執行此操作。輪詢完成允許調用線程在異步調用在 ThreadPool 線程上執行時繼續執行。

C# 
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() {
            // The asynchronous method puts the thread id here.
            int threadId;

            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.
            IAsyncResult result = caller.BeginInvoke(3000, 
                out threadId, null, null);

            // Poll while simulating work.
            while(result.IsCompleted == false) {
                Thread.Sleep(10);
            }

            // Call EndInvoke 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);
        }
    }
}

異步調用完成時執行回調方法

如果啓動異步調用的線程不需要是處理結果的線程,則可以在調用完成時執行回調方法。回調方法在 ThreadPool 線程上執行。

若要使用回調方法,必須將引用回調方法的 AsyncCallback 委託傳遞給 BeginInvoke。也可以傳遞包含回調方法將要使用的信息的對象。例如,可以傳遞啓動調用時曾使用的委託,以便回調方法能夠調用 EndInvoke。

C# 
using System;
using System.Threading;

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        // Asynchronous method puts the thread id here.
        private static int threadId;

        static void Main() {
            // Create an instance of the test class.
            AsyncDemo ad = new AsyncDemo();

            // Create the delegate.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
       
            // Initiate the asychronous call.  Include an AsyncCallback
            // delegate representing the callback method, and the data
            // needed to call EndInvoke.
            IAsyncResult result = caller.BeginInvoke(3000,
                out threadId, 
                new AsyncCallback(CallbackMethod),
                caller );

            Console.WriteLine("Press Enter to close application.");
            Console.ReadLine();
        }
        
        // Callback method must have the same signature as the
        // AsyncCallback delegate.
        static void CallbackMethod(IAsyncResult ar) 
        {
            // Retrieve the delegate.
            AsyncMethodCaller caller = (AsyncMethodCaller) ar.AsyncState;

            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, ar);

            Console.WriteLine("The call executed on thread {0}, with return value /"{1}/".",
                threadId, returnValue);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章