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线程
posted @ 2019-03-28 17:00  翻白眼的哈士奇  阅读(1678)  评论(0编辑  收藏  举报