python多进程变成学习之multiprocessing
来源:互联网 发布:js级联菜单 编辑:程序博客网 时间:2024/05/16 05:47
Python解释器有一个全局解释器锁(PIL—— Global Interpreter Lock),导致每个phthon进程中最多同时运行一个线程,因此Python多线程程序并不能改善程序性能,不能体现多核系统的优势。
什么是全局解释器锁GIL?
Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在任意时刻,只有一个线程在解释器中运行。对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
多线程环境中,Python虚拟机的工作方式:
1. 设置GIL2. 切换到一个线程去运行3. 运行: * 指定数量的字节码指令或者线程主动让出控制(可以调用time.sleep(0))4. 把线程设置为睡眠状态5. 解锁GIL6. 再次重复以上所有步骤
multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python内部编写的函数。该Process对象与Thread对象的用法相同,也有start(),run(),join()方法。此外multiprocessing保重也有Lock/Event/Semphore/Condition类(这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同明类一直。所以,multiprecessing的很大一部分与threading使用同一套API。multiprocessing可以有效的利用子进程,因此多处理器模块允许程序员充分利用多处理器,
使用共享api的注意事项:
* 在Unix平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie)。所以,有必要对每个Process对象调用join方法(实际上等同于wait)。对于多线程来说,由于只有一个进程,多以不存在此必要性。* multiprocessing提供了threading包中没有的IPC(比如pipe和queue),效率更高。应优先考虑pipe和queue,避免使用Lock/Event/Semaphore/Condition等同步方式(因为它们占据的不是用户进程的资源)。* 多进程应该避免共享资源。在多线程中,我们可以比较容易的共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。因此我们可以通过共享内存和Manager的方式在共享资源。但这样做提高了程序的复杂度,并因为同步的需要而减低了程序的效率。* Process.PID中保存有PID,如果进程还没有start(),则PID为None.
快速安装:
pip install mutiprocessing
multiprocessing支持三种启动流程,分别为‘spawn’,‘fork’,“forkserver”
spawn
父进程启动一个新的Python解释器, 子进程将只继承运行run()方法所需的资源。不继承父进程不必要的文件描述符和句柄(一种特殊的只能指针)。与使用fork或forkserver相比,使用此方法启动进程相当慢。在Unix和Windows上可用,Windows上为默认。
fork
父进程使用os.fork()来分叉Python解释器,子进程开始时,与父进程实际上是相同的。父进程所有资源都由子进程继承。这不能保证多线程的安全问题
forkserver
当程序启动并选择forkserver start方法时,将启动服务器进程。从那时起,每当需要新进程时,父进程连接到服务器,并请求它分配一个新进程。叉服务器进程是单线程的,因此它可以安全使用os.fork()。没有不必要的资源被继承。
如果要选择启动方法,必须在主模块中使用set_start_method方法,如:
if __name__ == '__main__': multiprocessing.set_start_method('spawn')
公共属性:
multiprocessing.current_process() -> Process #返回当前运行的子进程对象multiprocessing.cpu_count() -> int #返回宿主机CPU核心数multiprocessing.active_children() -> list #返回存活的子进程列表
多线程类
1.Process类,主要用于创建子进程
p = multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}) -> Process #创建子进程对象,target表示调用函数,name表示子进程名称,args表示调用函数传递的参数元组,kwargs表示调用函数传递的参数字典p.daemon = true -> boolean #设置或返回子进程是否随主进程结束,默认为false,主进程必须等待所有子进程结束后才结束,一旦设置为true,则一旦主进程执行完毕后,即使子进程还没执行完毕也强制结束,必须在start之前设置,可设置p.join来强制主进程等待子进程执行完毕p.join(timeout=None) #等待此子进程返回后再执行其它子进程/主进程,timeout为等待时间p.pid -> int/None # 返回子进程pidp.exitcode -> int/None #运行时为None,-N表示信号N结束p.is_alive() -> boolean # 返回进程是否存活p.start() -> None #启动子进程,会自动调用子类中的run方法p.terminate() -> None# 终止子进程 在读取进程共享数据时终止可能会造成数据损坏
Lock
锁视为了确保数据一致性,比如读写锁,和java中的锁概念是一样的
lock = multiprocessing.Lock()def func(lock): lock.acquire()#获取锁,使得其他进程无法抢占锁 """同步代码""" lock.release()其中acquire和release必须配对出现。SemaphoreSemaphore类主要用于控制同时对共享资源访问子进程数,如连接池最大连接数限制s = multiprocessing.Semaphore(value=1) -> Semaphore # 创建信号量对象,value表示同时对共享资源访问的子进程数
Event
e = multiprocessing.Event() -> Event # 创建信号对象,主要用于子进程之间同步通信e.set() -> None # 设置标志位e.clear() -> None # 清除标志位e.is_set() -> boolean #判断是否设置了标志位e.wait(self, timeout=None) -> None #阻塞当前子进程直到标志位被设置
IPC(Inter-Process Communication) 进程间的通信——Pipe&Queue
Piple(FIFO)
p = multiprocessing.Pipe(duplex=True) -> tuple说明: 创建通道对象,主要用于两个子进程之间的数据传递,返回管道的两个端对象1/2,如果duplex为true则全双工可以互相收发,否则1端只能接受消息,2端只能发送消息p[0/1].send(picklable) -> None说明: 发送数据支持任意可序列化对象p[0/1].recv() -> picklable说明: 如果没有消息可接收,recv会一直阻塞直至管道被关闭抛出EOFError异常
import multiprocessing as muldef proc1(pipe): pipe.send('hello') print('proc1 rec:',pipe.recv())def proc2(pipe): print('proc2 rec:',pipe.recv()) pipe.send('hello, too')if __name__ == '__main__': mul.freeze_support() pipe1,pipe2= mul.Pipe() #创建两个pipe对象 # Pass an end of the pipe to process 1 p1 = mul.Process(target=proc1, args=(pipe1,)) #创建p1线程 # Pass the other end of the pipe to process 2 p2 = mul.Process(target=proc2, args=(pipe2,)) #创建p2线程 p1.start() #调用线程1 p2.start() #调用线程2 p1.join() #这里等待线程1执行完成 p2.join() #等待线程2执行完成#输出: ('proc2 rec:', 'hello') ('proc1 rec:', 'hello, too') 为什么先输出的是proc2的?因为pipe.recv在接受的时候管道中没有数据,会进行阻塞,当线程二执行的时候,接收到线程1的数据输出,再给线程1发送数据,线程1中接收到数据之后打印
Queue
Queue与Pipe相类似,都是先进先出的结构。但Queue允许多个进程放入,多个进程从队列取出对象。Queue使用mutiprocessing.Queue(maxsize)创建,maxsize表示队列中可以存放对象的最大数量。
q = multiprocessing.Queue(maxsize=0) -> Queue说明: 创建队列对象,主要用于多个进程之间的数据传递q.full() -> boolean说明: 判断队列是否已满q.close() -> None说明: 关闭队列q.empty() -> boolean说明: 判断队列是否已空q.put(obj, block=True, timeout=None) -> None说明: 插入队列,block为False会立即抛出Queue.Full异常,否则会阻塞timeout时间,直到队列有剩余的空间,如果超时会抛出Queue.Full异常,还有一个同类方法q.put_nowait(obj)非阻塞插入立即抛Queue.Full异常q.get(block=True, timeout=None) -> None说明: 取出队列,block为false会立即抛出Queue.Empty异常,否则会阻塞timeout时间,直到队列有新对象插入,如果超时会抛出Queue.Empty异常,还有一个同类方法q.get_nowait()非阻塞读取立抛Queue.Empty异常
import multiprocessingimport time# 向queue中输入数据的函数def inputQ(queue): info = str(os.getpid()) + '(put):' + str(time.time()) queue.put(info) # 向queue中输出数据的函数def outputQ(queue,lock): info = queue.get() lock.acquire() print (str(os.getpid()) + '(get):' + info) lock.release() # Mainif __name__ == '__main__': multiprocessing.freeze_support() record1 = [] # store input processes record2 = [] # store output processes lock = multiprocessing.Lock() #使用锁方法输出错乱 queue = multiprocessing.Queue(3) # 输入进程 for i in range(10): process = multiprocessing.Process(target=inputQ,args=(queue,)) process.start() record1.append(process) # 输出进程 for i in range(10): process = multiprocessing.Process(target=outputQ,args=(queue,lock)) process.start() record2.append(process) for p in record1: p.join() queue.close() # 如果没有数据进入队列中则关闭队列 for p in record2: p.join()
Pool
from multiprocessing import Pooldef f(x): return x*xif __name__ == '__main__': with Pool(5) as p: print(p.map(f, [1, 2, 3]))
- python多进程变成学习之multiprocessing
- Python多进程(multiprocessing)学习总结
- Python 学习笔记 多进程 multiprocessing
- Python 学习笔记 多进程 multiprocessing
- Python 学习笔记 多进程 multiprocessing
- Python 学习笔记 多进程 multiprocessing
- Python多进程Multiprocessing学习笔记
- python多进程并发之multiprocessing
- Python多进程任务处理之multiprocessing
- Python多进程multiprocessing
- Python 多进程(multiprocessing)
- python 多进程 multiprocessing
- Python多进程并发(multiprocessing)
- Python多进程并发(multiprocessing)
- Python多进程并发(multiprocessing)
- Python多进程并发(multiprocessing)
- Python多进程并发(multiprocessing)
- Python多进程并发(multiprocessing)
- 阿里云CentOS7中Git和GitHub使用总结
- 关键路径图
- tomcat远程debug
- 页表实现从逻辑地址到物理地址的转换
- FrameLayout加RadioGroup实现底部点击切换
- python多进程变成学习之multiprocessing
- JVM terminated. Exit code=-1的解决方法
- malloc相关内容,你知道吗?
- postgres函数(双重循环)
- P1784 数独
- logging
- [高中]在泉五2009~2012大考成绩单和名次
- Unity优化杂谈2(MONO内存)
- 静态链表和动态链表的区别