并发编程小结
进程
进程不是什么具体的东西,而是只一个过程,即程序运行起来的过程,是一个资源集合
开启进程的过程
右键运行,操作系统给CPU发送请求,为程序开辟一个内存空间,然后把代码都放进去执行代码,执行过程也是cpu参与
PS:(如果是python的话,则会将解释器的代码也放进去,先执行解释器代码,再运行编写的代码)
特点
- 进程的内存空间彼此隔离,如果想通信,需要借助第三方(如队列,文件等)
- 主进程需要等待所有的子进程结束之后才会结束,即子进程全部运行完,主进程才算完成
multiprocessing重要的用法
- 进程p.join(),那么会等p进程运行结束才继续往下执行主进程
- 查看进程pid
- os.getppid()查看父进程的pid
- os.getpid()查看当前进程的pid
- p.pid()查看子进程的pid
- 守护进程:首先是一个进程,等到主进程的最后一行运行结束,守护进程也会结束
- 进程的互斥锁:一个进程拿到了锁之后,在他不释放之前,其他人是不能再次拿到这把锁的(对应acquire和release)
生产者消费者模型(一种思想)
生产者只负责生产,消费者只负责消费,彼此都达到了自己最大的效率
生产者 --->队列(盆)--->消费者
线程
线程是cpu最小的执行单位,如果把进程比作工厂里的车间,那么线程就是车间里面一个个的流水线
python里面使用的线程是操作系统的原生线程,每个进程有一个地址空间。默认有一个控制线程,cpu真正的执行单位是线程。
线程和进程的关系
进程盛装线程,相当于线程的一个容器。
进程 = 各种资源加线程
产生一个线程的过程
开进程自带一个控制线程,也可以通过代码来调用操作系统来开启线程,代码执行完了线程结束了。
论述进程和线程
- 谈到进程就应该想到资源,进程的周期其实就是资源的申请和销毁过程。
- 谈到线程就应该想到代码的执行,线程的周期其实就是代码的运行和结束
- 线程的创建速度要快于进程
- 开启子进程需要申请资源开辟空间 慢
- 开启子线程只是告诉操作系统一个执行方案 快
- 线程共享一个进程的内存资源,进程彼此内存资源隔离
threading的重要用法:
- 子线程.join() : 等待子线程运行结束.
- 守护线程(了解): 首先是一个线程, 守护的的是主进程的完整周期.
- 线程锁(互斥锁).
- 死锁问题: 互相都拿到了彼此想要往下执行的必需条件,互相都不放手里的锁头.
python的多进程VS多线程
大前提要知道:python的多线程无法利用多核优势实现并行,只能实现并发,原因是因为Cpython解释器有GIL锁,同一进程下的同一时间内只能有一个线程运行,多个线程就不能实现并行只能并发。
io密集型 适合用python的多线程处理.
计算密集型 适合用python的多进程处理.
进程池线程池
池子的概念就是为了把进程和线程的数量规定起来,超过了就会溢出,从而能达到限制进程数量和线程数量的作用。
有可能一次性要执行的任务有20个,假设超过了计算机能一次承受的范围,那么为了保证服务器不崩掉,就需要对执行的进程数或者线程数进行限制
协程
其实就是程序员为了实现单线程下的并发(从而能够提高效率),而实现的一种操作
对于单线程下,不可避免会有多个io操作,但是我们能在自己的程序中(即用户级别的程序而不是操作系统级别的程序)控制单线程下多个任务遇到io就能切换,这样就保证了该线程能够最大限度的处于就绪态,即随时都可以被cpu执行的状态,相当于我们在用户程序级别将自己的io操作最大限度的隐藏起来,对于操作系统来说:这哥们(该线程)好像是一直处于计算过程中,io比较少。
协程的本质就是在单线程下,用户自己控制一个任务遇到io阻塞了就切换另外一个任务去执行
解决方案
- 可以控制多个任务之间的切换,切换前将任务的状态保存下来(重新运行时,可以基于暂停的位置继续)
- 补充1,可以检测io 操作,遇到io时才切换
gevent模块
详见协程