16. python多进程总结
2020-05-04 本文已影响0人
花间派I风月
1. 启动多进程的方式
- os.fork 只支持Unix,不支持windows
- 使用multiprocessing模块: 创建Process的实例,传入任务执行函数作为参数
- 使用multiprocessing模块: 派生Process的子类,重写run方法
- 使用进程池Pool
2. 启动多进程注意
- multiprocessing是基于fork(),因为windows没有fork()函数但是可以通过在
__main__
中启动子进程来规避 - multiprocessing创建子进程时会在子进程空间中复制一份主进程的代码,全局变量在多个子进程之间不共享
- 多进程之间数据是隔离的
3. python守护进程
- 正常情况下,如果主进程代码执行完成,但是子进程还没有执行完成,则程序还不会退出,而是继续等待子进程。
- 当要实现子进程要随主进程结束而结束时就可以设置守护进程。
- 设置守护进程的方式是在start()之前设置
daemon = True
- p.terminate() 是终止一个进程,该代码执行后进程不是立刻结束,CPU还有一个调度的过程此时用p.is_alive()检查发现结果为True,time.sleep() 一秒后再用p.is_alive()检查会发现结果为False
4. python多进程锁
- Lock类与RLock类相同:由于进程之间随机调度:某进程可能执行n条后,CPU接着执行其他进程。为了多个进程同时操作一个内存中的资源时不产生混乱,我们使用锁。
- Lock类与RLock类的区别:无论是Lock还是RLock,提供的方法都非常简单,acquire和release。但是Lock和RLock的区别是什么呢?RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的锁。
5. python多进程信号量-Semaphore
- 信号量Semaphore是一个计数器,控制对公共资源或者临界区域的访问量,信号量可以指定同时访问资源或者进入临界区域的进程数。每次有一个进程获得信号量时,计数器-1,若计数器为0时,其他进程就停止访问信号量,一直阻塞直到其他进程释放信号量。
6.python多进程事件
- 多进程中的事件Event-进程之间的状态标记通信,它是由进程设置的信号标志,如果信号标志为真,则其他进程等待直到信号解除
- Event对象实现了简单的进程通信机制,它提供了设置信号,清除信号,等待等用于实现进程间通信的方法
- Event对象创建时默认信号设置为False。False时会在wait()处阻塞,True时不阻塞
7. python多进程之队列
- IPC(Inter-Process Communication)进程之间通信
- 队列先进先出
- Queue()实例化是可以传一个参数代表队列上限,如果不传或传负数都表示队列没有限制。
- 当队列容量不够时会阻塞
- Queue可以创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递
8. python多进程之JoinableQueue
- JoinableQueue 与Queue一样也是multiprocessing模块中的一个类,也可以用于创建进程队列。
- JoinableQueue 创建可连接的共享进程队列,队列允许队列的消费者通知生产者,队列数据已被成功处理完成。通知过程是使用共享的信号和条件变量来实现的。
9. python多进程之Pipe
- Pipe返回2个连接对象(conn1, conn2),代表管道的两端,默认是双向通信的,即conn1和conn2都可以收发消息。
- Pipe是数据不安全的,所以如果是多个进程之间同时收发消息时,需要自己加锁以达到数据安全。
- 如果是生产者或消费者中都没有使用管道的某个端点,就应将它关闭。这也说明了为何在生产者中关闭了管道的输出端,在消费者中关闭管道的输入端。如果忘记执行这些步骤,程序可能在消费者中的recv()操作上挂起。
- 管道是由操作系统进行引用计数的,必须在所有进程中关闭管道后才能生成EOFError异常。因此,在生产者中关闭管道不会有任何效果,除非消费者也关闭了相同的管道端点
10. python多进程之Pool
- 在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?
- 首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。那么我们要怎么做呢?
- 这样就引入了进程池,进程池是指定义一个进程池,在里面放上固定数量的进程,有需求来了,就拿进程池中的一个进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。
- 如果有很多任务需要执行,进程池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。
11.python多进程之Manager
- Python中提供了强大的Manager类,专门用于实现多进程之间的数据共享;
- Manager类是数据不安全的;
- Mangaer类支持的类型非常多,如:value, Array, List, Dict, Queue, Lock等。
- Manager 类包含的常用方法和属性与Multiprocessing中其他常用类的方法属性一致。
12.python多进程之回调函数
- 需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数
- 我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果。
- 子进程执行返回的结果做为回调函数的参数传入。
- 回调函数是在主进程中执行的。回调函数适用于子进程数多且耗时时间长的场景。