通過委托來實現異步 Delegate的BeginInvoke和EndInvoke


什么是.net的異步機制呢?

解釋這個話題之前,先讓我們來看看同步執行的程序

https://github.com/chucklu/Test/blob/master/DotNet4.5開發指南/並行處理和並發/異步編程模式/APM/SyncProcedure/Program.cs

 static class SyncTest
    {
        public static void Method()
        {

            Console.WriteLine("SyncTest類中的Method()函數的線程ID是{0}", Thread.CurrentThread.ManagedThreadId);//Environment.CurrentManagedThreadId
            if (Thread.CurrentThread.IsThreadPoolThread)//判斷當前線程是否托管在線程池上
            {
                Console.WriteLine("SyncTest類中的Method()函數的線程托管於線程池");
            }
            else
            {
                Console.WriteLine("SyncTest類中的Method()函數的線程沒有托管在線程池上");
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Program類中的Main()函數的線程ID是{0}", Thread.CurrentThread.ManagedThreadId);//Environment.CurrentManagedThreadId
            if (Thread.CurrentThread.IsThreadPoolThread)//判斷當前線程是否托管在線程池上
            {
                Console.WriteLine("Program類中的Main()函數的線程托管於線程池");
            }
            else
            {
                Console.WriteLine("Program類中的Main()函數的線程沒有托管在線程池上");
            }
            Console.WriteLine();

            SyncTest.Method();//調用靜態類的靜態方法

            Console.Read();//阻塞,確保能看到上面的打印信息
        }
    }

執行結果如下圖所示

從圖中可以看出,在主函數中調用另外一個類SyncTest的方法,

進入方法Method的時候,此方法還是和Main函數在同一個線程上執行的

並且該線程不是托管在線程池上的線程

 

 

接下來寫一個通過委托,進行異步執行的方法

https://github.com/chucklu/Test/blob/master/DotNet4.5開發指南/並行處理和並發/異步編程模式/APM/AsyncProcedure/Program.cs

不要嘗試去查看BeginInvoke和EndInvoke的實現,右鍵,轉到定義,是看不到的。這兩個方法是CLR為委托類型添加的

/// <summary>
    /// 聲明一個委托 委托的名字是AsyncHandler
    /// </summary>
    /// <param name="name"></param>
    public delegate void AsyncHandler();//委托的聲明方式類似於函數,只是比函數多了一個delegate關鍵字
    
    static class AsyncTest
    {
        public static void Method()
        {
            Console.WriteLine("AsyncTest類中的Method()函數的線程ID是{0}", Thread.CurrentThread.ManagedThreadId);//Environment.CurrentManagedThreadId
            if (Thread.CurrentThread.IsThreadPoolThread)//判斷當前線程是否托管在線程池上
            {
                Console.WriteLine("AsyncTest類中的Method()函數的線程托管於線程池");
            }
            else
            {
                Console.WriteLine("AsyncTest類中的Method()函數的線程沒有托管在線程池上");
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Program類中的Main()函數的線程ID是{0}", Thread.CurrentThread.ManagedThreadId);//Environment.CurrentManagedThreadId
            if (Thread.CurrentThread.IsThreadPoolThread)//判斷當前線程是否托管在線程池上
            {
                Console.WriteLine("Program類中的Main()函數的線程托管於線程池");
            }
            else
            {
                Console.WriteLine("Program類中的Main()函數的線程沒有托管在線程池上");
            }
            Console.WriteLine();

            //把Method 方法分配給委托對象
            AsyncHandler async = AsyncTest.Method; //

            //發起一個異步調用的方法,返回IAsyncResult 對象
            IAsyncResult result = async.BeginInvoke(null,null);

            //這里會阻礙線程,直到方法執行完畢
            async.EndInvoke(result);

            Console.Read();
        }
    }

運行結果如下圖所示

從上圖可以看出,委托的BeginInvoke,是新開了一個線程運行方法,並且該線程是托管在線程池上的

 

 

 

 

上面兩個代碼的示例,區別在於,第二個使用的是委托的BeginInvoke方法

通過反編譯工具,我們可以查看委托具體做了什么,一般.net Reflector不錯,最近新發現一個叫ILSpy的,開源的反編譯工具

https://github.com/icsharpcode/ILSpy   官網的.sln是VS2013的,如果不想自己編譯的,也可以去官網下載編譯好的exe程序

官網鏈接是http://ilspy.net/     右上角有一個Download Binaries,點擊下載就可以了

接下來上圖,反編譯的結果

從上圖可以發現AsyncHandler委托的結構如下

public extern AsyncHandler(object @object, IntPtr method);
public virtual extern IAsyncResult BeginInvoke(AsyncCallback callback, object @object);
public virtual extern void EndInvoke(IAsyncResult result);
public virtual extern void Invoke();

而且可以發現繼承層次,AsyncHandler從MulticastDelegate繼承,再上層是Delegate類(注意,大寫的Delegate表示的是類,而不是delegate關鍵字)

 

去msdn上找了相關信息

 

 

 Delegate類

public abstract class Delegate : ICloneable,ISerializable

The Delegate class is the base class for delegate types.
Delegate類是delegate類型的基類
However, only the system and compilers can derive explicitly
from the Delegate class or from the MulticastDelegate class. 然后只有系統和編譯器才可以從Delegate類或者MulticastDelegate類進行派生
It
is also not permissible to derive a new type from a delegate type. 從委托類型派生一個新類型也是不允許的
The Delegate
class is not considered a delegate type; it is a class used to derive delegate types. Delegate類並不是委托類型,它只是一個用於派生委托類型的類。
Most languages implement a
delegate keyword, and compilers for those languages are able to derive from the MulticastDelegate class; therefore, users should use the delegate keyword provided by the language. 大多數語言實現了delegate關鍵字,並且這些語言的編譯器是能夠從MulticastDelegate類進行派生的,所以,開發者們應該使用開發語言所提供的delegate關鍵字 The common language runtime provides an Invoke method for each delegate type, with the same signature as the delegate. CLR為每一個委托類型提供了一個Invoke方法,並且該方法和delegate擁有相同的簽名 The common language runtime provides each delegate type with BeginInvoke and EndInvoke methods, to enable asynchronous invocation of the delegate. CLR為每一個委托類型提供了BeginInvoke和EndInvoke方法,來確保委托的異步調用

MulticastDelegate類
public abstract class MulticastDelegate : Delegate

MulticastDelegate is a special class. Compilers and other tools can derive from this class, but you cannot derive from it explicitly. The same is true of the Delegate class.
多播委托是一個特殊的類。編譯器或者其他工具,可以從從這個類派生,但是你不能顯式地從這個類派生。同樣的規則適用於Delegate類。

In addition to the methods that delegate types inherit from MulticastDelegate, the common language runtime provides two special methods: BeginInvoke and EndInvoke.
delegate關鍵字聲明的委托,不但繼承了多播委托的方法,並且CLR還提供了兩個特殊的方法BeginInvoke和EndInvoke

更多關於BeginInvoke和EndInvoke的信息可以參見此鏈接[使用異步方式調用同步方法]http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.110).aspx

 使用委托進行異步編程http://msdn.microsoft.com/zh-cn/library/22t547yb(v=vs.110).aspx

 

轉載自http://www.cnblogs.com/AndyHuang/archive/2008/12/24/1361267.html   (有自己的修改和理解)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM