前序:按顺序阅读更好
进程与线程
1. 定义
-
进程:进程是指在系统中正在运行的一个应用程序,如微信、QQ等app都是一个进程.
-
线程:线程是进程的基本执行单元,处理器调度的基本单位. 一个进程的所有任务都在线程中执行.进程至少要有一条线程,程序启动会默认开启一条线程,这条线程被成为主线程或UI线程
2. 关系与区别
- 同一进程的线程共享本进程的地址空间和资源(如内存、I/O、CPU等),而进程之间则是独立.
- 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉,所以多进程要比多线程健壮.进程切换时,消耗的资源大、效率高。所以设计到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程而不能用进程.
- 进程是独立运行的,线程必须依赖于进程
任务和队列
-
任务: 就是执行操作的意思,换句话说就是你在线程中执行的那段代码(在 GCD 中是放在 block 中的)。执行任务有两种方式:同步执行 和 异步执行。两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。
-
同步执行(sync):
- 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
- 只能在当前线程中执行任务,不具备开启新线程的能力。
-
异步执行(async):
-
异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务.
-
可以在新的线程中执行任务,具备开启新线程的能力。
-
在io等待的时候,同步不会切走,浪费了时间。 如果都是独占cpu 的业务, 在单核情况下 多线和单线 没有区别。
-
-
队列:(Dispatch Queue):这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)的原则。GCD 中有两种队列串行队列和并发队列。两者都符合 FIFO(先进先出)的原则。两者的主要区别是:执行顺序不同,以及开启线程数不同。
-
串行队列(Serial Dispatch Queue):每次只有一个任务被执行。让任务一个接着一个地执行。(只开启一个线程,一个任务执行完毕后,再执行下一个任务)
-
并发队列(Concurrent Dispatch Queue):可以让多个任务并发(同时)执行。(可以开启多个线程,并且同时执行任务)
-
所以任务和队列的组合方式有 4 种
- 同步执行 + 并发队列
- 异步执行 + 并发队列
- 同步执行 + 串行队列
- 异步执行 + 串行队列
| 队列/执行 | 并发队列 | 串行队列 | 主队列(特殊的串行队列) | 全局队列(特殊的并发队列) |
|---|---|---|---|---|
| 同步(sync) | 没有开启新线程,串行执行任务 | 没有开启新线程,串行执行任务 | 死锁卡住不执行 | 没有开启新线程,串行执行任务 |
| 异步(async) | 有开启新线程,并发执行任务 | 有开启新线程,串行执行任务 | 没有开启新线程,串行执行任务 | 有开启新线程,并发执行任务 |
注意
并发队列的并发功能只有在异步(dispatch_async)方法下才有效。
主队列是特殊的串行队列, 全局队列是特殊的并发队列(系统提供的)
主队列的实质上就是一个普通的串行队列,主线程 中调用 主队列+同步执行 会导致死锁问题。 这是因为 主队列中追加的同步任务 和 主线程本身的任务 两者之间相互等待,阻塞了主队列,最终造成了主队列所在的线程(主线程)死锁问题.
并行与并发
1. 并行与并发的区别
-
并发(concurrency):把任务在不同的时间点交给处理器进行处理。在同一时间点,任务并不会同时运行。
-
并行(parallelism):把每一个任务分配给每一个处理器独立完成。在同一时间点,任务一定是同时运行
单核处理器,多线程只能并发执行(并发原理就是cpu快速来回切换);
多核处理器可以实现真正的并行,也就是真正的同时运行
既然单核处理器不能实现真正的并行,那么单核cpu有必要多线程吗?
通常一个任务不光 cpu 上要花时间,io上也要花时间(例如去数据库查数据,去抓网页,读写文件等)。一个进程在等 io 的时候,cpu 是闲置的,另一个进程正好可以利用 cpu 进行计算。 多个进程一起跑,可以把 io 和 cpu 都跑满了。
如果都是独占cpu 的业务,在单核情况下多线程和单线程没有区别
现在一般都是虚拟资源,资源有弹缩机制,所以一般该跑多线程的时候就可以跑多线程
2. 面试题:多线程为什么能提高执行效率?
1.在多核处理器上,将要执行的任务分成多个可并行执行的线程,就可以提高执行效率。
2.在单核处理器上,多线程只能并发执行,而不是并行,并发原理,其实就是cpu快速来回切换,在特定的时间执行特定的某一个任务,并发执行存在这线程间上下文切换的问题,会消耗一定的时间。如果不考虑阻塞,多线程并发执行其实比单线程执行更加耗费时间,线程过多也会造成cpu负荷过大,并且线程占用内存资源,创建销毁线程也都是需要开销的。
多线程通过提高cpu利用率来提高效率。数据库访问、磁盘io等操作的速度比cpu执行代码的速度慢很多,单线程环境下,这些操作会阻塞程序的执行,导致cpu空转,等待着上述操作完成,因此对于会产生这些阻塞的程序来说,使用多线程可以避免在等待期间cpu的空转,提高cpu的利用率。
考虑到多线程存在的一些缺点,现在的网络服务器为了支持大量并发多不是靠多线程或多进程,而采用其他的技术如异步i/o