欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python多进程模块(multiprocessing)的基本使用方法(想要轻松上手的不要错过啦!)

程序员文章站 2022-03-31 11:29:43
...

python语言中默认含有的全局解释器锁(即GIL),由于全局解释器锁的存在,每个运行任务只能在获取全局解释器锁之后才能开始运行,使用多线程时某线程在执行100条字节码后,当前线程就自动释放GIL锁,让别的线程有机会执行。因此即使使用多线程,也是不能真正达到并行的。正因为这样的限制使得Python多线程有时候显得很无用。当然在某些I/O密集型任务中还是可以使用多线程方法的,因为在等待时间其余线程可以继续执行任务。
在需要利用多核CPU完成某些计算密集型任务时,就需要用到多进程方法了,python中的多进程大概有os.fork()、multiprocessing、concurrent.future()模块。其中os.fork()模块的使用场景较少,并且只能运行于类unix系统上,另外两个则可移植性更强,使用也较为方便,本文主要介绍multiprocessing模块的几种使用方式。
调用multiprocessing模块创建多进程任务一般有两个方法即Process(创建进程)与Pool(创建进程池)。
需要注意多进程产生的进程都是有进程号的,是能够实时监控到的。多进程也是一般用于函数环境的!


Process类

# 创建一个进程(仅介绍,创建一个进程没啥意义嘛,哈哈!)
import multiprocessing
def test(i):
	print(i)
if __name__ == '__main__':
	process1 = multiprocessing.Process(target=test,args=('jack',))  
	# 这就是开启进程的方法,target为要运行的函数,args为需要向将要运行的函数传入的参数。
	# 单个参数后加上,(逗号)表示传入的参数是可以迭代的,单个参数时必须加上,
	process1.start()   # 开始刚刚创建的新进程
	process1.join()     
	'''
	join是用于等待所有子进程结束后才结束主进程的方法,若有疑问可查看我之前的介绍join方法的文章
	https://blog.csdn.net/keepaware/article/details/108432899
	'''
# 创建多个进程
import multiprocessing
def test(i):
	print(i)
if __name__ == '__main__':
	record = []   # 创建一个record列表用于储存产生的进程,利于后续的join操作
	for p in range(4):  # 使用for循环用于后续创建四个进程
		process = multiprocessing.Process(target=test,args=(p,))  
		''' 
		这里要注意,如果每次的参数都输入一样的,这样每个进程都会运行一样的任务,也就是说每个进程都是从
		头开始运行。这就可能会导致结果不尽人意,不要问我为啥知道,呜呜!因此需要自己设计方法来避免这个
		坑,例如制作一个参数列表,从列表中提取每个参数。后续还有map方法也可匹配列表
		'''
		process.start()   
		# 开始创建的新进程,此处不调用join是因为调用后主进程会等待每个子进程结束后才开始下个子进程
		record.append(process)   # 将每个创建的进程都放入record列表中
	for process in record:
		process.join()     
		# 从record列表中提取每个子进程使用join方法,此时子进程都已经在运行了,再等待每个子进程都结束即可

Pool类(进程池)

Pool.map()
# 进程池即创建一个进程库,事先设置好需要多少进程,从进程库中提取这些已创建的进程即可。
# Pool.map()
import multiprocessing
def test2(i):
	print(i)
if __name__ == '__main__':
	list1 = list(range(5))  # 创建一个列表,map方法会用到
	pool1 = multiprocessing.Pool(processes=4)  # 创建一个进程池,这里创建了含有4个进程的进程池
	pool1.map(test2,list1)   
	'''
	对pool1使用map方法,在这个例子中即形成(test2(0),test2(1),test2(2),test2(3),test2(4) 这些任务)
	这些将执行的任务是按顺序执行的,也就是说进程1执行test2(0),进程2执行test2(1),进程3执行test2(2)进程4执行test2(3),还多出一个任务则需要等待,等到某个进程提前结束了就再执行这个任务。
	这样的话相当于一个进程执行一次单独的任务,十分方便某些任务
	如果函数有返回值即return,还可以使用result = pool1.map(test2,list1)获取每个进程的返回值,
	但是这里是所有返回值在一起,需要自己对其按需处理。
	'''
	pool1.close()  # close方法用于关闭进程池,即恢复到没有子进程的情况
	pool1.join() 
Pool.apply_async()

除了apply_async外还有apply,不过apply已经近乎被淘汰了,因为apply是阻塞的,需要一个进程结束才能开始下个进程。此方法使用方式类似于process方法,是一种异步非阻塞执行多进程的方式,但是需要在进程池的基础下进行

# 使用Pool.apply_async() 创建一个进程
import multiprocessing
def test3(i):
	print(i)
if __name__ == '__main__':
	with multiprocessing.Pool(processes=4) as pool:  # 使用with方法不用后续关闭Pool
		result = pool.apply_async(test3,args=('jack',))  # 此处同上,参数不变的话执行的是同一任务
		res = result.get()  # get方法可以获取进程的返回值,此处可以使用res进行后续操作		
# 创建多个进程
def test4(i):
	print(i)
if __name__ == '__main__':
	res_list = []
	with multiprocessing.Pool(processes=4) as pool:
		for p in range(10):
			ret = pool.apply_async(test4,args=(p,))
			ret_list.append(ret)
		for ret in ret_list:
			ret.get()

若是想对不同的任务进行多进程操作,也是相当简单的,因为实际上每个多进程操作结束后都是会关闭或者join的,因此在每个多进程操作结束后再开启新的多进程任务即可
例:

import multiprocessing
def test5(i):
	print(i)
if __name__ == '__main__':
	list1 = list(range(10))
	res_list = []
	for item in list1:	
		with multiprocessing.Pool(processes=4) as pool:
			for p in range(item):
				ret = pool.apply_async(test5,args=(p,))
				ret_list.append(ret)
			for ret in ret_list:
				ret.get()
		
相关标签: python python