总结进程,线程区别:
进程:
- 进程是由操作系统分配资源的基本单位。程序运行时,程序所使用到的的内存和系统资源 称之为进程
- 进程的5种状态:新建、就绪、等待、执行、死亡。或者说三种状态(就绪、等待、运行)
- 一个进程里面至少有一个线程
- 因为进程有内存空间,多进程相对于多线程来说,所以比较占用内存
- 进程通信方式:管道,FIFO,消息队列,信号,共享内存,socket套接字,stream流;
线程:
- 线程是CPU执行和调度的基本单位。相当于一个执行路径
- 线程不能独立存在,依靠进程,开销比较小
- 线程之间可共享资源,但是多线程可能会出现资源竞争,采用线程同步机制可解决。最简单的同步机制是互斥锁
- 线程通信方式:如果多个线程在同一进程内,即共享内存,共享资源,全局变量,队列
同步和异步可以理解为发出调用的行为方式。
同步:发出一个调用,没有得到结果之前,该调用不返回,一旦调用返回就得到了返回值。
异步:发出一个调用,立即返回,没有返回结果。可以通过状态或通知来通知调用者。
阻塞和非阻塞关注的是等待状态。
阻塞:调用结果返回之前,线程会一直在等待结果。阻塞当前线程往后执行。
非阻塞:调用结果返回之前,线程不等待结果。该调用不会阻塞当前线程,可以做其它事情。
多进程和多线程使用的场景:
多进程适用于cpu密集型的任务,就是有cpu来执行计算任务,比如赋值拷贝、大量运算、排序查找。此时cpu一直在运转,可以使用多核cpu来轮转执行。
多线程适用于IO密集型的任务,涉及到网络延迟,硬盘/内存读写操作,此时cpu大部分时间都在等待IO操作,并没有发挥极致作用,所以可以使用多线程。I/O就是input输入/output输出
多线程需要注意的是 python的GIL锁:
对一个进程而言,不管有多少线程,任一时刻,只会有一个线程在执行。如果是CPU密集型的线程,其效率不仅仅不高,反而有可能比较低。所以python多线程比较适用于IO密集型的程序
面试题之多进程,多线程通信:
多进程通信方式:
- 管道: 又分为无名管道和有名管道。无名管道只能用在亲缘关系(如:父子)进程之间通信。 有名管道无所谓
- 消息队列: 消息队列存放在内核中并由消息队列标识符标识,是不同进程之间可实现共享资源一种机制。
- 共享内存: 指一个进程映射一段能被其它进程所访问的内存
- 信号量: 一般结合共享内存使用
- 信号
- 套接字: 可实现多台机器上的进程通信
多线程通信:
- 全局变量: 定义全局变量,多线程之间都可以使用
- 共享内存:
- 消息队列
- 锁机制:互斥锁提供了以排他方式防止数据结构被并发修改的方法
守护进程:守护进程会在主进程代码执行结束后就终止,进程之间是互相独立的,主进程代码运行结束,守护进程随即终止,但是非守护的进程会执行完。
守护线程: 守护线程会在主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕。
其实无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁 。
守护进程
def ppx1():
print("皮皮虾1开始")
time.sleep(1)
print("皮皮虾1结束")
def ppx2():
print("皮皮虾2开始")
time.sleep(3)
print("皮皮虾2结束")
if __name__ == '__main__':
p1 = Process(target=ppx1)
p2 = Process(target=ppx2)
p1.daemon = True
p1.start()
p2.start()
# p1.join() # 主进程会等待p1执行完。 可以打开注释看一下效果
print("main-------")
结果是:
main-------
皮皮虾2开始
皮皮虾2结束
(因为p1,p2都是子进程需要开辟空间,所以cpu不会等待,会往下先执行输出main------,此时主进程代码运行完毕,p1也就销毁掉,但是p2会继续执行)
守护线程:
def ppx_1():
print("皮皮虾1开始")
time.sleep(1)
print("皮皮虾1结束")
def ppx_2():
print("皮皮虾2开始")
time.sleep(3)
print("皮皮虾2结束")
if __name__ == '__main__':
t1 = Thread(target=ppx_1)
t2 = Thread(target=ppx_2)
t2.daemon = True
t2.start()
t1.start()
print("main-------")
结果是:
皮皮虾2开始
皮皮虾1开始
main-------
皮皮虾1结束
(因为t1,t2线程都在一个进程里面,cpu不等待而是直接执行t2,t1,main---,t2需要三秒,t1需要1秒,执行完t1即结束,不会等待守护线程)