C#委托同步異步說明,並比較control調用Invoke和BeginInvoke的異同


一.委托的同步和異步:

1.同步

使用Invoke調用同步,或直接寫fun1("func"),在fun1.Invoke這一步會明顯的阻塞線程

使用:

static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "Main";

            //定義一個帶返回值的委托
            var fun1 = new Func<string, int>(x =>
            {
                Thread.Sleep(1000);
                Console.WriteLine(x);
                Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");
                return 1;
            });

            fun1.Invoke("fun1");

            Console.WriteLine("Main");
            Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");
            Console.ReadKey();
        }

  

 運行結果:

結果說明:

同步委托運行在主線程上

2.異步

使用BeginInvoke來調用異步,EndInvoke來獲取返回值,AsyncCallback定義異步完成回調函數

使用:

        static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "Main";

            //定義一個帶返回值的委托
            var fun1 = new Func<string, int>(x =>
            {
                Thread.CurrentThread.Name = "fun1";
                Console.WriteLine(x);
                Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");
                return 1;
            });

            fun1.BeginInvoke("fun1", t =>
            {
                //var fun2 = t.AsyncState as Func<string, int>;//如果不是lambda表達式需要用該方式獲得委托
                //獲取返回值
                int ret = fun1.EndInvoke(t);
                Console.WriteLine($"callback return:{ret}");
                Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");

            }, null);

            Thread.Sleep(1000);
            Console.WriteLine("Main");
            Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");
            Console.ReadKey();
        }

  

運行結果:

 

結果說明:

異步委托並不是運行在主線程上,而是運行在獨立的線程上,是異步執行的

 二.control的Invoke和BeginInvoke

1.Invoke

使用:

        private void button1_Click(object sender, EventArgs e)
        {
            Thread.CurrentThread.Name = "UIThread";
            this.Invoke(new Action(() =>
            {
                Thread.Sleep(5000);
                Debug.WriteLine($"Invoke ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");
            }));

            Debug.WriteLine($"Main ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");
        }

  運行結果:

結果說明:

可以明顯的感到Invoke阻塞了界面5s后,才執行后面的代碼

Invoke內的委托在UI線程上執行,是同步的

 2.BeginInvoke

使用:

        private void button1_Click(object sender, EventArgs e)
        {
            Thread.CurrentThread.Name = "UIThread";

            this.BeginInvoke(new Action(() =>
            {
                Debug.WriteLine($"BeginInvoke ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");
            }));

            Debug.WriteLine($"Main ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}");
            Thread.Sleep(5000);
        }

  

  運行結果:

結果說明:

可以明顯看到界面卡了5s后,才先執行的BeginInvoke內的委托

結論:BeginInvoke內的委托在UI線程上執行,並不是異步,只是放在UI線程中最后執行。

 三.結論

delegate.Invoke 運行在主線程上,同步執行,並立即執行,會阻塞主線程
delegate.BeginInvoke 運行在獨立線程上,異步執行, 並立即執行,不會阻塞主線程
Control.Invoke 運行在UI線程上,同步執行,並立即執行,會阻塞UI線程
Control.BeginInvoke 運行在UI線程上,不是異步執行,等UI線程其他操作完成才執行,會阻塞UI線程


免責聲明!

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



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