目录 1、多进程 示例:创建多进程 示例:创建多进程获取子进程任务结果 2、进程池 同步 异步 多个不同的任务方法执行同一个数据源返回不同的结果 多个数据源,执行相同的任务方法校验,发现不合格,就退出不再执行 回调函数-接收子进程返回结果,实时处理

1、多进程 示例:创建多进程

import os
import time
from multiprocessing import Process


def task(num):
   print(f"父进程:{os.getppid()}-创建子进程{os.getpid()},执行任务:{num}")
   time.sleep(3)


if __name__ == '__main__':
   start = time.time()
   p_list = []
   print("当前环境进程:", os.getpid())
   for i in range(5):
       p = Process(group=None, target=task, args=(i,), kwargs={}, name=f"进程名:校长{i}")
       p.start()
       p_list.append(p)
  [o.join() for o in p_list]
   print(f"父进程等待每个子进程任务结束,总耗时:{time.time()-start}")
   
   
"""
结果如下:
当前环境进程:14276
父进程:14276-创建子进程8492,执行任务:0
父进程:14276-创建子进程15080,执行任务:1
父进程:14276-创建子进程14920,执行任务:2
父进程:14276-创建子进程13528,执行任务:4
父进程:14276-创建子进程13452,执行任务:3
父进程等待每个子进程任务结束,总耗时:3.257822036743164

因为每个子进程内存空间是隔离的,所以此时是无法得到每个任务的结果的,一般想得到结果可以采用队列的方式保存!
"""  

示例:创建多进程获取子进程任务结果


import os
from multiprocessing import (Process, Queue)


def task(num, q):
   print(f"父进程:{os.getppid()}-创建子进程{os.getpid()},执行任务:{num}")
   q.put(f"任务:{os.getpid()}执行结果:{num}")


if __name__ == '__main__':
   q_obj = Queue()
   p_list = []
   for i in range(5):
       p = Process(target=task, args=(i, q_obj))
       p.start()
       p_list.append(p)

   # 遍历每个子进程,确认其执行完毕
  [o.join() for o in p_list]
   # 遍历每个子进程,获取对应子进程执行任务结果
   response = [q_obj.get() for j in p_list]
   print(f"子进程执行的结果集为:{response}")

"""
执行结果为:
父进程:14472-创建子进程10172,执行任务:1
父进程:14472-创建子进程13464,执行任务:0
父进程:14472-创建子进程1548,执行任务:3
父进程:14472-创建子进程10692,执行任务:4
父进程:14472-创建子进程13412,执行任务:2
子进程执行的结果集为:['任务:10172执行结果:1', '任务:13464执行结果:0', '任务:1548执行结果:3', '任务:10692执行结果:4', '任务:13412执行结果:2']
"""

2、进程池 特点:同时开启指定数量的进程(一般CPU个数),并行执行任务,用于高计算,并行,有任务执行返回值

同步 任务结果顺序是按照提交任务结果的顺序,同步也就是按进程创建的顺序

import os
import time
from multiprocessing import Pool

# 获取cpu个数
print(os.cpu_count())


def task(flag):
   print(f"进程:{os.getppid()},创建子进程:{os.getpid()},执行任务{flag}")
   time.sleep(2)
   return flag


if __name__ == '__main__':
   start = time.time()
   pool = Pool(processes=os.cpu_count())
   job_list = range(10)
   results = []
   for i in job_list:
       # apply的方式
       ret = pool.apply(task, (i,))  # 同步,进程池是有返回值的
       
       # map的方式
       # ret = p.map(task, (job,)) # 同步,一共执行10个任务
       
       results.append(ret)
   pool.close()   # 关闭 并不是进程池中的进程不工作了,而是关闭了进程池,让任务不能再继续提交了
   pool.join()    # 等待这个池中提交的任务都执行完,表示等待所有子进程中的代码都执行完 主进程才结束
   
   print(f"apply-任务执行结果合集:{results}")   ----> 任务执行结果合集:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
   print(f"apply-总耗时:{time.time()-start}")  ----> 总耗时:20.55962562561035
       
   print(f"map-执行的结果为:{result_list}")   ---> 执行的结果为:[[0], [1], [4], [9], [16], [25], [36], [49], [64], [81]]
   print(f"map-总耗时:{time.time() - start}") ---> 总耗时:20.336746215820312
	 

异步 任务结果是按照子进程提交任务的顺序,结果顺序不可控,要求任务关联性不高


import os
import time
from multiprocessing import Pool

# 获取cpu个数
print(os.cpu_count())


def task(flag):
   print(f"进程:{os.getppid()},创建子进程:{os.getpid()},执行任务{flag}")
   time.sleep(2)
   return flag


if __name__ == '__main__':
   start = time.time()
   pool = Pool(processes=os.cpu_count())
   job_list = range(10)
   results = []
   for i in job_list:
       # apply_async方式
       ret = pool.apply_async(task, (i,))  # 异步,一次并行执行池子里配置的数量的任务
       
       # map_async方式
       ret = p.map_async(task, (job,))  # 同步,一共执行5个任务
       results.append(ret)
   pool.close()
   pool.join()
   ret = [job.get() for job in results]   # 异步需要调用get方法
   print(f"apply_async-任务执行结果合集:{ret}")        ----> 异步时,任务执行结果合集:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
   print(f"apply_async-总耗时:{time.time() - start}") ----> 异步时,总耗时:4.462151765823364  
       
   print(f"map_async-执行的结果为:{result_list}")   ---> 执行的结果为:[[0], [1], [4], [9], [16], [25], [36], [49], [64], [81]]
   print(f"map_async-总耗时:{time.time() - start}") ---> 总耗时:4.353601694107056    
# 在异步提交中,可以不用join(),主进程会执行完代码,但会等待进程池中的任务结束,才结束

多个不同的任务方法执行同一个数据源返回不同的结果


# 对同一份请求报文,执行不同的校验,返回对应的结果
import os
from multiprocessing import Pool


def task1(data):
   print(f"子进程:{os.getpid()},执行任务")
   print(data.get("num"))  # 5
   code = 1
   if data["num"] > 10:
       code = 0
   return dict(code=code)


def task2(data):
   print(f"子进程:{os.getpid()},执行任务")
   code = 1
   if data["num"] < 9:
       code = 0
   return dict(code=code)


def task3(data):
   print(f"子进程:{os.getpid()},执行任务")
   code = 1
   if 2 < data["num"] < 9:
       code = 0
   return dict(code=code)


if __name__ == '__main__':
   
   pool = Pool(os.cpu_count())
   jobs = [task1, task2, task3]
   results = []
   data = {"num": 5}
   for i in jobs:
       # apply_async方式
       ret = pool.apply_async(i, (data,))
       
       results.append(ret)
   pool.close()
   pool.join()
   print(f"结果集为:{[j.get() for j in results]}")  ---> 结果集为:[{'code': 1}, {'code': 0}, {'code': 0}]
   
   # map_async方式
   pool = Pool(os.cpu_count())
   jobs = [task1, task2, task3]
   results = []
   data = {"num": 5}
   for i in jobs:
       ret = pool.map_async(job, (data,))
       results.append(ret)
   pool.close()
   pool.join()
   print(f"结果集为:{[j.get() for j in results]}")  ---> 结果集为:[[{'code': 1}], [{'code': 0}], [{'code': 0}]
	 

多个数据源,执行相同的任务方法校验,发现不合格,就退出不再执行 只要得到自己想要的结果,就结束,节约资源

import os
import time
from queue import Queue
from multiprocessing import Pool

"""不同的数据源,执行相同的任务"""


def task(data):
   time.sleep(0.05)
   print(data)
   if data == 5:
       return False
   else:
       return True


if __name__ == '__main__':
   pool = Pool(os.cpu_count())
   q = Queue()
   data_list = range(1000)
   for i in data_list:
       ret = pool.apply_async(task, args=(i,))
       q.put(ret)
   pool.close()
   while True:
       p_result_obj = q.get()
       flag = p_result_obj.get()
       print(flag)
       if flag is False:
           # 如果校验失败,则退出不再执行后面的
           print("发现校验失败,结束进程池中的所有子进程")
           pool.terminate()
           break

   pool.join()
   print("执行后面的逻辑")
   
# 升级版本:多进程+多线程
import os
import time
from queue import Queue
from threading import Thread,get_ident
from multiprocessing import Pool


def task(data):
   time.sleep(0.05)
   print(f"主进程{os.getppid()},创建子进程{os.getpid()},执行任务{data}")
   print(data)
   if data == 5:
       return False
   else:
       return True


def pool_th(data_list, q, pool):
   for i in data_list:
       # 创建多个子进程,异步只是将任务添加到队列,还没有执行完
       q.put(pool.apply_async(task, args=(i,)))


def result_th(q, p):
   while True:
       flag = q.get().get()  # 获取子进程结果
       print(f"在子线程{get_ident()}中获取子进程执行的结果进行判断:{flag}")
       if not flag:
           p.terminate()  # 结束所有子进程
           break


if __name__ == '__main__':
   result_q = Queue()
   pool = Pool()
   data_list = range(1000)
   # 开启多线程
   t1 = Thread(target=pool_th, args=(data_list, result_q, pool))
   t2 = Thread(target=result_th, args=(result_q, pool))
   t1.start()
   t2.start()
   t1.join()
   t2.join()
   pool.join()
   print("执行后面的逻辑")
   
# 这里有个通病,那就是结束进程池子进程任务时,有的子进程已经执行了,因为每个子进程执行的结果插入顺序不是有序的,而我们需要的那个结果也许虽然按任务来说在前面,但它执行的时间并不一定在前面

回调函数-接收子进程返回值,实时处理 定义:将一个进程的执行结果的返回值,会当callback参数来执行配置的callback函数,从而减少获取子进程结果等I/O操作浪费的时间

作用:进程池中的任何一个任务一旦处理完了,就立即告知主进程,我已执行完毕,你可以处理我的结果了,主进程则调用一个函数【你配置的回调函数】去处理该结果。

注意:回调函数是没有返回值,所以回调函数一般可用于对子进程结果的判断后,然后写库等等操作

from multiprocessing import Pool
import time
import os


def task(num):
    time.sleep(2)
    print(f"父进程{os.getppid()},子进程:{os.getpid()}执行任务{num}")
    if num > 3:
        res = {"job_num": num, "result": 0}
    else:
        res = {"job_num": num, "result": 1}
    return res


def back(args):
    print(f"回调即时处理每个子进程返回的结果{args},其父进程为:{os.getpid()}")
    if args["result"] == 0:
        print("写库")
    else:
        print(f"记录日志,任务{args['job_num']},执行失败,结果为:{args['result']}")


if __name__ == '__main__':
    print(f"当前进程:{os.getpid()},父:{os.getppid()}")
    jobs = range(10)
    p = Pool(os.cpu_count())
    for job in jobs:
        p.apply_async(func=task, args=(job,), callback=back)
    p.close()
    p.join()