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()

  

 

posted on 2022-02-20 10:46  秋不语  阅读(290)  评论(0)    收藏  举报

导航