C#委托同步异步说明,并比较control调用Invoke和BeginInvoke的异同

 


一.委托的同步和异步:

1.同步

使用Invoke调用同步,或直接写fun1("func"),在fun1.Invoke这一步会明显的阻塞线程

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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定义异步完成回调函数

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

使用:

1
2
3
4
5
6
7
8
9
10
11
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

使用:

1
2
3
4
5
6
7
8
9
10
11
12
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 @   翻白眼的哈士奇  阅读(1688)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示