python多进程multiprocessing包中queue、pipe、manager模块的功能介绍(超易懂哦!)

在这里插入图片描述

python多进程主要用于解决python自身含有的GIL(即全局解释器锁)所导致的不能并行任务的问题,之前已经介绍了multiprocessing包的基本使用方式,本文简要介绍一下multiprocessing包中含有的几个模块pipe(管道)、queue(队列)、manager,这几个模块在某些较为复杂的实际应用中还是很有用处的。


queue(队列)

python自身本来就带有queue模块,此模块正如其名,发挥的是队列功能,当然这种队列的传递也是能够发挥通信作用的。python官方文档的解释是queue模块实现多生产者,多消费者队列,能够在多个生产者和消费者之间通信。当信息必须安全的在多线程之间交换时,它在线程编程中是特别有用的。此模块中的 Queue 类实现了所有锁定需求的语义。

简单说queue其实就像进程或线程锁一样,起到对信息的保护作用。由于队列的存在,python函数中的生产者函数及消费者函数能够准确、有确定方向的进行通信。使这些需要被传递的信息不会因为多线程或多进程的存在而出错。queue储存某些生产者函数产生的信息,再将这些信息一起传递给消费者函数。当然这些函数可以是在不同的进程中运行的,从而达到进程间通信的效果。使用了队列后就不会有信息提前或者滞后到达消费者进程处,这样也就不容易导致信息出错或者紊乱。

multiprocessing中queue模块包含的方法有qsize()(返回队列包含元素的多少)、empty()(即给出队列是否为空的判断,空为True)、full()(即给出队列是否已满的判断,因为开始的时候设置队列可以设置最大拥有元素的多少)、put()(即将元素放入队列)、get()(从队列中获取元素,注意每获取一个队列中元素就减少一个)、close()(表示当前队列不再放入新的元素)。

例:

import multiprocessing

def test(q):
	for i in range(10):
		q.put(i)   # 将元素放入queue
	q.close()
	
def get_q(q):
	while not q.empty():    # 判断队列是否为非空,非空才继续执行下一步
		res = q.get()       # 获取一个元素
		print(res)
		# print(q.qsize())
		
if __name__ == '__main__':
	q = multiprocessing.Queue()      # 定义queue,这里可以传入参数,即队列所含最大元素量
	p1 = multiprocessing.Process(target=test,args=(q,))   # 多进程
	p2 = multiprocessing.Process(target=get_q,args=(q,))
	# 此例仅为介绍用,实际应用时创建的进程可以有丰富的功能,只需要将queue作为一个参数传入进程即可。
	p1.start()
	p2.start()
	p1.join()
	p2.join()	

结果:

在这里插入图片描述

pipe(管道)

pipe(管道)在编程语言中也是用于通信功能,即将某函数产生的结果通过管道的一端传递给管道的另一端,这就是管道名称的来源。python中管道一般用于多进程操作,可以用于在进程间传递消息。

与队列不同的地方是pipe能进行双向通信,但是队列只能单向传递消息。

例:

import multiprocessing

def test1(conn):
	conn.send('test1传送到:jack')      # 传递一个信息‘jack’
	conn.send('test1传送到:mary')	   # 传递另个信息‘mary’	
	print(conn.recv())     # 获取从管道的另一端发送来的第一个值
	print(conn.recv())     # 获取从管道的另一端发送来的第二个值
	
def test2(conn):
	conn.send('test2传送:你好')      # 传递一个信息‘你好’
	conn.send('test2传送:HELLO')    # 传递另个信息‘HELLOprint(conn.recv())    # 获取从管道的另一端发送来的第一个值
	print(conn.recv())    # 获取从管道的另一端发送来的第二个值

if __name__ == '__main__':
	p_conn,c_conn = multiprocessing.Pipe()  # 定义一个管道的两端,之后将这两端传出去
	p1 = multiprocessing.Process(target=test1,args=(p_conn,))    # 把一端给test1
	p2 = multiprocessing.Process(target=test2,args=(c_conn,))    # 另一端给test2
	p1.start()
	p2.start()
	p1.join()
	p2.join()
	# 这样就将test1与test2函数进行了管道传输,test1的内容传给了test2,test2的内容传给了test1。
	# test1与test2被分配到了不同的进程,因此这样相当于就进行了多进程中进程间的通信。

结果:

在这里插入图片描述

manager(共享内存管理)

manager模块用于多进程中共享内存的管理,其实也就是全局变量的管理。默认情况下子进程产生的全局变量仅子进程自身可以使用,主进程是获取不到子进程中全局变量的变化的。这也是因为当下使用的多核电脑的每个核都是分开工作的,即每个子进程都在不同核上工作,因此要设置全局变量就不是默认的,需要额外设置(注意:这一点不同于多线程,多线程中子线程的全局变量主线程能识别到,因为是单核运行)。

除了manager外,multiprocessing包还含有value、array也可以用于共享内存的处理。

使用value、array的例子:

import multiprocessing

def test(v,a):
	v.value = 123         			# 这里修改传入的value的值
	for i in range(len(a)):			# 这里逐个修改传入的array中的值
		a[i] = 'o'

if __name__ == '__main__':
	v = multiprocessing.Value('d')    # 将v指定为Value
	a = multiprocessing.Array('u','nihao')   # 将a指定为字符型array,官方文档提示说后续u可能被删除
	process = multiprocessing.Process(target=test,args=(v,a)) # 传入test函数,开启子进程
	process.start()
	process.join()
	print(v.value)     				  # 打印出v的值,检查是否被改变 
	print(a[:])                       # 打印出a的序列,检查是否改变

结果:

在这里插入图片描述
python官方文档说明manager支持类型有: list 、 dict 、 Namespace 、 Lock 、 RLock 、 Semaphore 、 BoundedSemaphore 、 Condition 、 Event 、 Barrier 、 Queue 、 Value 和 Array 。

此处以list和dict为例:

import multiprocessing
def test(list1,dict1):
	dict1['name1'] = 'jack'     # 增加dict1的内容
	dict1['name2'] = 'mary'     
	list1.reverse()             # 将list1中的内容颠倒
if __name__ == '__main__':
	with multiprocessing.Manager() as manager:     # 引入manager
		list1 = manager.list(range(5))             # 设置list1和dict1为共享对象
		dict1 = manager.dict()
		p = multiprocessing.Process(target=test,args=(list1,dict1))  # 传入函数中对list1与dict1修改
		p.start()
		p.join()
		print(list1)  # 检查是否修改
		print(dict1)

结果:

在这里插入图片描述

叮!

其实除了上面介绍的这些模块外还有Lock()模块也是很重要的一个模块,但是使用起来是较为简单的,这里就不再介绍了。另外还看到了semaphore模块,此模块称为信号量,用于控制线程数,即只有线程获取了信号后才能运行否则就阻塞。semaphore模块是为了防止线程数太多导致任务出错或机器故障而设计的。

参考:https://docs.python.org/zh-cn/3.6/library/multiprocessing.html#multiprocessing.Queue.empty
参考:https://blog.csdn.net/haeasringnar/article/details/79917057

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值