python 多进程

  • 多进程
    • multiprocessing
    • Pool
    • 子进程
    • 进程间通信
    • 小结
  • 多进程

  • Unix/Linux系统中提供一个fork() 系统调用函数,可以fork 出子进程
    • 调用一次返回两次,父进程(当前进程) + 子进程(复制)
    • 在子进程中返回0, 父进程中返回子进程 ID
    • 父进程可以fork多个子进程, 需要记下所有的子进程
    • 子进程通过getppid() 拿到父进程的进程ID
    • import os 
      
      # only works on Unix/Linux/Mac
      pid = os.fork() 
      if pid == 0:
      	print('当前为子进程id: %s , 父进程为:%s '%(os.getpid(), os.getppid()))
      else:
      	print('当前进程id:%s,创建了子进程,id 为: %s'%(os.getpid(), pid) )
      
  • multiprocessing

    • multiprocessing 模块是跨平台版本的多进程模块( windows上无法使用fork)
    • from multiprocessing import Process
      import os
      
      # 子进程要执行的代码
      def run_proc(name):
        print("子进程%s(%s))运行"%(name, os.getpid()))
        
      if __name__ == '__main__':
        print('当前进程%s' %s os.getpid())
        p = Process(target=run_proc, args('test,'))
        print('子进程即将启动')
        p.start() # 启动进程,较fork()更简单
        p.join() # 等待子进程结束, 通常用于进程就同步
        print('子进程结束')
      
  • Pool

    • 启动大量子进程, 可以使用进程池的方法批量创建
    • from multiprocessing import Process
      import os, time, random
      
      def long_time_task(name):
        print('运行任务%s(%s)...'%(name, os.getpid()))
        start = time.time()
        time.sleep(random.random() * 3)
        end = time.time()
        print('任务%s 耗时 %0.2f 秒'%(name,(end-start) )
              
      if __name__ == '__main__':
              print('当前进程(%s)'% os.getpid())
              p = Pool(4) # 设置同时运行4个进程的限制, 默认大小CPU的核数
              for i in range(5):
              	p.apply_async(long_time_task, args=(i,))
              print('等待所有子进程运行结束')
              p.close() # 必须先调用, 调用后不能够在添加进程
              p.join() # 等待所有子进程执行结束
              print('所有子进程运行结束')
      
  • 子进程

    • subprocess 模块可以方便地启动一个子进程,然后控制子进程输入输出
    • 实现命令 nslookup www.python.org
    • import subprocess
      
      print('$ nslookup www.python.org')
      r = subprocess.call(['nslookup', 'www.python.org'])
      print('退出码', r)
      
    • 实现命令 nslookup
    • import subprocess
      
      print('$ nslookup')
      p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
      output, err = p.communicate(b'set q=mx\npython.org\nexit\n')
      print(output.decode('utf-8'))
      print('推出码', p.returncode)
      # 执行命令 nslookup 后, 手动输入 'set q=mx\npython.org\nexit\n'  
                              
      
  • 进程间的通信

    • multiprocessing 模块提供了QueuePipes等多种方式来交换数据
    • Queue 读取数据
    • from multiprocessing import Process, Queue
      import os,time, random
      
      def write(q):
        print('用于写入数据的进程:%s' % os.getpid())
        for value in ['A', 'B', 'C']:
          print('把%s放入队列'%s value)
          q.put(value)
          time.sleep(random.random())
          
      def read(q):
        print('用于读取数据的进程:%s'%s os.getpid())
        while True:
          value = q.get(True)
          print('队列中获取值: %s' %s value)
          
      def __name__ == '__main__':
        q =Quee()
        pw = Process(target=write, args=(q,))
        pd = Process(target=write,args=(q,))
        pw.start() # 启动进程, 写入
        pr.start() # 启动进程, 读取
        pw.join()  # 等待写入结束
        pr.terminate() # while True 为死循环, 强行终止
      
  • 小结

    • Unix/Linux 系统, 可以使用fork() 实现多进程
    • 实现跨平台的多进程,可以使用multiproessing 模块
      1. multiprocessing 在win系统, 需要模拟fork的效果。
      2. 父进程所有Python对象都必须通过pickle 序列化在传入子进程
    • 进程间通信是通过QueuePipes等实现的
posted @ 2022-03-07 21:46  lghgo  阅读(32)  评论(0编辑  收藏  举报