python 多进程与进程池
多进程:
导入包:from multiprocessing import Process, Queue,Manager
函数式使用法:
def abc(abc,bcd):
print(abc,bcd)
return abc,bcd
基本调用:
res = Process(target=abc,args=(abc,bcd)) # 传入函数名,参数使用元组的形式写后面
res.start() # 启动
res.join() # 等待进程运行结束
res.close() # 关闭进程
多次调用:
res_list=[]
for i in range(20):
res = Process(target=abc,args=(i,i+1))
res.start()
res_list.append(res)
for res in res_list:
res.jion()
类式调用:
在类中写一个run() 函数,然后调用run,方法同上
消息队列:
q = Queue(N)
q.maxsize # 队列最大数,python3.7中使用
q._maxsize # python 3.9中使用
q.qsize() #队列中当前消息数
q.full() # 队列满 返回True
q.empty() # 队列空 返回True
q.put('abc') # 向队列中添加消息
q.get() # 从队列中取消息
进程池:
导入包:from concurrent.futures import ProcessPoolExecutor
pool = ProcessPoolExecutor(5) # 创建容量为5的进程池,默认大小为cpu核心数
def abc(name,age):
print(name,age)
return name,age
def callback(a):
for i in a.result():
print(i)
return 'abc'
pool.submit(abc,name,age) # abc 为函数名,name,age为函数的参数,有几个跟几个
res = poo.submit(abc,name,age).add__done_callback(callback)
# 提交任务时后面可以跟一个回调函数,abc的返回值以元组的形式直接传递给回调函数,回调函数返回值可能是一个元组(待测试)
消息队列与进程池结合使用:
优点:只使用进程池,无法获取等待执行的任务数量
结合消息队列,可以获得队列中等待的数量
可能出现的问题:从队列向进程池提交任务时,由于队列中的数量是变化的,有可能造成提交数大于进程池大小
def putq(n,q): #用于向队列中添加任务的函数
j = 0
while True:
for i in range(n):
j += 1
q.put(j)
time.sleep(10)
def pro(runningnum): # 向进程池中提交的任务
print('pro q.get',runningnum)
time.sleep(1) # 延时1秒
print() # 输出空行,便观察
def startpro(pro, q): # 进程池主函数,在主进程中直接调用,如果另外开一个进程可能报错
Num = 4 # 进程池大小
pool = ProcessPoolExecutor(Num) # 创建进程池
runningnum = 0 # 进程池中正在运行的任务数
plist = [] # 用于存放 进程池 中运行的任务
while True:
# 如果队列非空,并且进程池运行任务数不满,则提交任务
if (not q.empty()) and (runningnum < Num):
numtosubmit = Num - runningnum # 进程池 的空余数
if numtosubmit > q.qsize(): # 空余数与队列中任务数比较
numtosubmit = q.qsize() # 空余数大于任务数则提交队列中的任务数
else:
pass
for i in range(numtosubmit): # 循环提交
runningnum += 1 # 运行数 + 1
a = q.get() # 从队列中取任务作为向进程池提交任务的参数
res = pool.submit(pro, a)
plist.append(res) # 把进程池任务对象存入列表中
elif q.empty():
pass
for res in plist: # 如果进程池中的任务对象完成,则从列表中删除并把运行数-1
if res.done():
print(res)
plist.remove(res)
runningnum -= 1
if __name__ == '__main__': # 进程池方式
q = Manager().Queue(20) # 此处需要先调用Manager,否则会报错
n = 10 # 队列大小
p = Process(target=putq, args=(10, q)) # 另开一个进程,间隔10秒向队列中添加任务
p.start()
time.sleep(2)
startpro(pro, q) # 开始进程池进程
队列与多进程结合:
def add_item(item,q): # 向队列中提交任务
print('pro q.put',item)
q.put(item)
time.sleep(1) # 延时1秒
print() # 输出空行,便观察
def pro(runningnum): # 向进程中提交的任务
print('pro q.get',runningnum)
time.sleep(1) # 延时1秒
print() # 输出空行,便观察
def startpro(pro, n,q): # 多进程主函数,在主进程中直接调用
plist = [] # 用于存放 进程池 中运行的任务
while True:
# 如果队列非空,并且进程池运行任务数不满,则提交任务
if (not q.empty()) and (len(plist) < Num):
numtosubmit = Num - len(plist) # 进程池 的空余数
if numtosubmit > q.qsize(): # 空余数与队列中任务数比较
numtosubmit = q.qsize() # 空余数大于任务数则提交队列中的任务数
else:
pass
for i in range(numtosubmit): # 循环提交
a = q.get() # 从队列中取任务作为向进程池提交任务的参数
res = Process(target=startpro,args=(len(plist))
res.start()
plist.append(res) # 把进程任务对象存入列表中
# 注意此处缩进,在需要启动的进程启动完成后,跳出if 后调用jion
for res in plist: # 提交完成后,把进程jion
res.jion()
for res in plist: # 如果进程中的任务对象完成,则从列表中删除并把运行数-1
if res.is_alive():
res.close()
plist.remove(res)
continue
if q.empty() and len(plist) == 0:
print('all is over')
break
else:
continue
if __name__ == '__main__': # 多进程方式
n = 10 # 队列大小
q = Manager().Queue(n) # 此处需要先调用Manager,否则会报错
p = Process(target=add_item, args=(n, q)) # 另开一个进程,间隔10秒向队列中添加任务
p.start()
time.sleep(2) # 延时 等待任务添加到队列中
p.jion()
startpro(pro, n,q) # 开始进程池进程
p.close()
浙公网安备 33010602011771号