BeginInvoke、IAsyncResult、EndInvoke、AsyncCallback

 

一、BeginInvoke

語法:

IAsyncResult delegate.BeginInvoke([parameters], AsyncCallback callback, object @object);

using System;
using System.Threading;

namespace ConsoleApp1
{
    public class AsyncDemo
    {
        public string TestMethod(string name, int callDuration)
        {
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + " " + name + " 開始");
            Thread.Sleep(callDuration);
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + " " + name + " 結束");
            return name + " complete";
        }
    }

    public delegate string AsyncMethodCaller(string name, int callDuration);

    class Program
    {
        public static void Main()
        {
            AsyncDemo ad = new AsyncDemo();
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            IAsyncResult result10 = caller.BeginInvoke("任務10秒", 10000, null, null);
            IAsyncResult result15 = caller.BeginInvoke("任務15秒", 15000, null, null);
            IAsyncResult result20 = caller.BeginInvoke("任務20秒", 20000, null, null);

            Thread.Sleep(5000);
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + "主執行緒5秒");

            Console.ReadKey();
        }
    }
}

執行畫面為

說明:

1、範例上共有四個要執行的項目,分別是「主執行緒5秒」、「任務10秒」、「任務15秒」、「任務20秒」,

如果是使用同步作法的話,則總共會花 5 + 10 + 15 + 20 = 50 秒的時間;

但使用非同步作法的話,由於要執行的四個項目會同時間開始處理,

故最多只會花到 20 秒時間,這就是同步與非同步的最大不同之處。

2、此範例是利用委派所提供的 BeginInvoke 方法去實作非同步,

BeginInvoke 方法的意思為將一任務加入非同步處理。

3、注意 BeginInvoke 只支援在 .Net Framework 4.8 以下,而不能在 .Net Core 上跑。

 

二、IAsyncResult

IAsyncResult 是一個介面,有以下屬性

 

而 AsyncResult 是實作類別

 

AsyncState 屬性是用來取得 user-defined object。

 

你可以利用 IsCompleted 屬性來輪詢「任務20秒」是否完成任務。

using System;
using System.Threading;

namespace ConsoleApp1
{
    public class AsyncDemo
    {
        public string TestMethod(string name, int callDuration)
        {
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + " " + name + " 開始");
            Thread.Sleep(callDuration);
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + " " + name + " 結束");
            return name + " complete";
        }
    }

    public delegate string AsyncMethodCaller(string name, int callDuration);

    class Program
    {
        public static void Main()
        {
            AsyncDemo ad = new AsyncDemo();
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            IAsyncResult result10 = caller.BeginInvoke("任務10秒", 10000, null, null);
            IAsyncResult result15 = caller.BeginInvoke("任務15秒", 15000, null, null);
            IAsyncResult result20 = caller.BeginInvoke("任務20秒", 20000, null, null);

            while (result20.IsCompleted == false)
            {
                Thread.Sleep(1000);
                Console.WriteLine(".");
            }

            Thread.Sleep(5000);
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + "主執行緒5秒");

            Console.ReadKey();
        }
    }
}

執行畫面為

 

三、EndInvoke

語法:

delegate_type delegate.EndInvoke(IAsyncResult result);

using System;
using System.Threading;

namespace ConsoleApp1
{
    public class AsyncDemo
    {
        public string TestMethod(string name, int callDuration)
        {
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + " " + name + " 開始");
            Thread.Sleep(callDuration);
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + " " + name + " 結束");
            return name + " complete";
        }
    }

    public delegate string AsyncMethodCaller(string name, int callDuration);

    class Program
    {
        public static void Main()
        {
            AsyncDemo ad = new AsyncDemo();
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            IAsyncResult result10 = caller.BeginInvoke("任務10秒", 10000, null, null);
            IAsyncResult result15 = caller.BeginInvoke("任務15秒", 15000, null, null);
            IAsyncResult result20 = caller.BeginInvoke("任務20秒", 20000, null, null);

            string returnValue = caller.EndInvoke(result20);
            Console.WriteLine(returnValue);

            Thread.Sleep(5000);
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + "主執行緒5秒");

            Console.ReadKey();
        }
    }
}

執行畫面為

說明:

1、在 Main() 裡,當執行到 EndInvoke() 方法時,將會等待其任務完成後才會繼續執行 Main() 之後的內容;

其 EndInvoke() 方法的意思就是等待指定任務完成才會繼續執行。

 

四、AsyncCallback

AsyncCallback 是個委派型別,其用來當一任務完成時,執行所指定的方法。

using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace ConsoleApp1
{
    public class AsyncDemo
    {
        public string TestMethod(string name, int callDuration)
        {
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + " " + name + " 開始");
            Thread.Sleep(callDuration);
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + " " + name + " 結束");
            return name + " complete";
        }
    }

    public delegate string AsyncMethodCaller(string name, int callDuration);

    class Program
    {
        public static void Main()
        {
            AsyncDemo ad = new AsyncDemo();
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            IAsyncResult result10 = caller.BeginInvoke("任務10秒", 10000, null, null);
            IAsyncResult result15 = caller.BeginInvoke("任務15秒", 15000, null, null);
            IAsyncResult result20 = caller.BeginInvoke("任務20秒", 20000, null, null);

            IAsyncResult result = caller.BeginInvoke("任務25秒", 25000, new AsyncCallback(CallbackMethod), "(((任務25秒)))");

            Thread.Sleep(5000);
            Console.WriteLine("ManagedThreadId:" + Thread.CurrentThread.ManagedThreadId + "主執行緒5秒");

            Console.ReadKey();
        }

        public static void CallbackMethod(IAsyncResult ar)
        {
            //從 IAsyncResult 轉型成 AsyncResult
            AsyncResult result = (AsyncResult)ar;

            //取得本身的委派方法
            AsyncMethodCaller caller = (AsyncMethodCaller)result.AsyncDelegate;

            //目地只是為了取得其回傳值
            string returnValue = caller.EndInvoke(ar);

            //Gets a user-defined object
            string oUserDefined = (string)ar.AsyncState;

            Console.WriteLine(oUserDefined + "-" + returnValue);
        }
    }
}

執行畫面為

 

參考資料:

AsyncResult Class