测试开发进阶(十)
进程之间通信
进程之间通信:使用队列
queue模块中的队列,只能用于一个进程中,各个线程之间进行通信
进程模块中的Queue:可以用于多个进程之间进行通信
⚠️注意点:使用的时候要使用参数传递到各个进程任务中
1 | from multiprocessing import Queue |
1 | from multiprocessing import Process, Queue |
work1获取数据0
work1获取数据1
work1获取数据2
work1获取数据3
work1获取数据4
协程
- 协程,又称微线程
- 协程是python中另外一种实现多任务的方式,只不过比线程更小,占用更小执行单元(理解为需要的资源)
- 它自带CPU上下文,这样只要在合适的时间,我们就可以把一个协程切换到另一个协程,只要这个过程保存或恢复CPU上下文那么程序还是可以运行的
通俗的理解
在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己决定
协程和线程差异
在实现多任务时,线程切换从系统层面远不止保存和恢复CPU上下文这么简单,操作系统为了程序的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换比较耗性能。但是协程的切换之间单纯的操作CPU的上下文,所以一秒钟切换个上百万次性能都扛得住。
1 | g1 = (i for i in range(10)) |
<generator object
at 0x114203138>
<generator object gen at 0x1142031b0>
协程的实现
1 | def work1(): |
work1:0
work2:0
work3:0
work1:1
work2:1
work3:1
work1:2
work2:2
work3:2
work1:3
work2:3
work3:3
work1:4
greenlet
1 | pip install greenlet |
1 | import time |
0
0
1
1
2
2
3
3
4
4
gevent
gevent其原理就是当一个greenlet遇到IO(input output输入输出,比如网络,文件操作等)操作时,比如访问网络,就自动切换到其他greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent自动切换协程,保证总有greenlet在运行,而不是等待IO
1 | pip install gevent |
等待需要使用gevent.sleep(0.1)
1 | import gevent |
work1:0
work2:0
work1:1
work2:1
work1:2
work2:2
work1:3
work2:3
work1:4
work2:4
修改work2的等待时间为0.4秒
1 | import gevent |
work1:0
work2:0
work1:1
work1:2
work1:3
work2:1
work1:4
work2:2
work2:3
work2:4
如果需要使用time.sleep
但是要完成切换需要使用猴子补丁
注意:猴子补丁在多线程任务时会出现异常!!!!!
1 | from gevent import monkey |
1 | import time |
发送IO
1 | import time |
进程池
close
:关闭进程池,该进程池不再接收新的任务
1 | import os |
进程ID:64232,work1:0
进程ID:64233,work1:0
进程ID:64234,work1:0
进程ID:64232,work1:1
进程ID:64233,work1:1
进程ID:64234,work1:1
进程ID:64232,work1:2
进程ID:64234,work1:2进程ID:64233,work1:2进程ID:64232,work1:3
进程ID:64234,work1:3
进程ID:64233,work1:3
进程ID:64232,work1:4
进程ID:64234,work1:4进程ID:64233,work1:4
进程池之间的队列:
1 | from multiprocessing import Manager |
线程池
- 内置模块
1 | from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor |
- 第三方模块
1 | import threadpool |
进程线程协程比较
- 进程是资源分配的单位
- 线程是操作系统调度的单位
- 进程切换需要的资源最大,效率很低
- 线程切换需要的资源一般,效率一般(在不考虑GIL的情况下)
- 协程切换任务资源很小,效率高
- 多进程,多线程根据cpu核数不同可能是并行的,但是协程是在一个线程中的,所以是并发
- python中的线程由于GIL锁的存在,不能实现并行