zoukankan      html  css  js  c++  java
  • 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线程
  • 相关阅读:
    如何选择合适的开源消息中间件
    使用Rest访问Redis中的数据
    论消息队列在分布式系统的重要性
    grub-install: warning: this GPT partition label contains no BIOS Boot Partition; embedding won’t be possible Ubuntu使用BIOS启动时, GPT分区表下安装grub2报错 的解决办法
    Linux Ubuntu 16.04 启动后 桌面崩溃
    Linux Ubuntu 1604 grub2 rescue mod 启动
    EF自动探测更改
    C# 使用OracleParameter传递参数提示缺少表达式
    Gitlab安装后 500 错误 PostGre数据库无法启动
    DevExpress GridControl GridView多选状态下,代码赋值FocusedRowHandle,样式无变化
  • 原文地址:https://www.cnblogs.com/yaosj/p/10616192.html
Copyright © 2011-2022 走看看