毕业好多年,从一开始面试起就很多面试官喜欢问这个问题。其实也是说的不是很清晰,似懂非懂,今天我就把这个好好的梳理一下,形成一个知识节点。我在网上也搜索了一下,关于同步异步、多线程有很多实例,我今天就是把我的理解进行口语化进行描述,让大家容易理解,也是让自己记忆更深刻。所以一下概念都是自己的理解,如需要官方解释请左转gg。
概念
1、进程--线程--多线程
- 进程:程序在机器上运行时全部占用计算机资源、虚拟的数据的集合。
- 线程:进程在相应操作时一个执行的动作或者一个任务,同时也包含计算机的资源信息。
- 句柄:其实是一个long数字,是程序所需要资源的ID,可以理解为页面的窗体、按钮等信息
- 多线程:一个进程中多个线程同时运行。
估计说了这些概念,还是不容易理解。用计算机“”任务管理器“”大家就容易明白。
线程池
顾名思义,就是管理线程的程序,类似一个线程池子。线程池主要有两个好处:
- 避免线程创建和销毁的开销。
- 自动缩放:可以按需增减线程的数量。
总之,Windows系统自带了线程池的功能,通常情况下,你不可能有更好的实现。所以只需了解如何使用。
Windows的线程池有两种,分别是非托管线程池和托管线程池(即.NET线程池)
2、并行和并发
不知道有没有想过为什么计算机可以多线程呢?
- 多个CPU的核可以并行工作。
比如我的电脑就是4个内核8个逻辑处理器,这里8个就是指的8个模拟核。如果8个核在同一进程中同时进行计算,则就是多核工作。
并行:多核之间同时运行称为并行。
- 因为一个CPU本身的计算量就很庞大,为了提高利用率,CPU都是分片处理的。比如我的电脑边写文章,边听歌。一个1S的处理能力分成1000份,则第一份去处理word,第二份处理播放软件,第三份又处理word,第四份处理播放软件……依次不断进行。因为时间分片比较短,人根本不可能察觉。所以电脑就给人的感官就是既可以写word又可以听歌,都是同时进行的。
从长时间段来看:感觉就是多个任务在并发执行。
从微时间段来看:一个物理CPU同一时间只能处理一个任务。
并发:一个CPU分片运行的称为并发。
3、同步和异步
同步方法:调用在程序继续执行之前需要等待同步方法执行完毕返回结果
异步方法:在被调用之后立即返回以便程序在被调用方法完成其任务的同时执行其它操作。
下面直接撸代码,这样直接又可观。
同步代码:
private void Button_SyncClick(object sender, RoutedEventArgs e) { Console.WriteLine($"===== 同步调用 SyncInvokeTest Start,ID: {Thread.CurrentThread.ManagedThreadId.ToString("000")} {DateTime.Now.ToString("HH:mm:ss fff")}"); for (int i = 0; i < 5; i++) { Dothings(i.ToString()); } Console.WriteLine($"===== 同步调用 SyncInvokeTest End, ID: {Thread.CurrentThread.ManagedThreadId.ToString("000")} {DateTime.Now.ToString("HH:mm:ss fff")}"); }
异步代码:
private void Button_AsyncClick(object sender, RoutedEventArgs e) { Console.WriteLine($"===== 异步调用 AsyncInvokeTest start,ID: {Thread.CurrentThread.ManagedThreadId.ToString("000")} {DateTime.Now.ToString("HH:mm:ss fff")}"); for (int i = 0; i < 5; i++) { Action<string> action = this.Dothings; action.BeginInvoke("", null, null); } Console.WriteLine($"===== 异步调用 AsyncInvokeTest End, ID: {Thread.CurrentThread.ManagedThreadId.ToString("000")} {DateTime.Now.ToString("HH:mm:ss fff")}"); }
好似操作:
private void Dothings(string name) { Console.WriteLine($"******* 方法调用 Dothings start,ID: {Thread.CurrentThread.ManagedThreadId.ToString("000")} {DateTime.Now.ToString("HH:mm:ss fff")}"); Thread.Sleep(2000); //模拟该方法运行2秒 Console.WriteLine($"******* 方法调用 Dothings end, ID: {Thread.CurrentThread.ManagedThreadId.ToString("000")} {DateTime.Now.ToString("HH:mm:ss fff")} {name}"); }
分别执行结果如下:
同步:
异步:
已上图可见,同步是在一个线程里,依次完成的。而异步是多个线程,主线程(001)直接就执行了,后续分配5个子线程依次完成无需等待。
(未完,后续补上其他多线程逻辑)