• 多进程


    多进程

    1, multiprocessing模块介绍

    • multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。
    • multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
    • 需要再次强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内

    2,Process类

    1,源码解析

    • class Process():
          name: str
          daemon: bool
          pid: Optional[int]
          exitcode: Optional[int]
          authkey: bytes
          sentinel: int
          # TODO: set type of group to None
          def __init__(self,
                       group: Any = ...,
                       target: Optional[Callable] = ...,
                       name: Optional[str] = ...,
                       args: Iterable[Any] = ...,
                       kwargs: Mapping[Any, Any] = ...,
                       *,
                       daemon: Optional[bool] = ...) -> None: ...
          def start(self) -> None: ...
          def run(self) -> None: ...
          def terminate(self) -> None: ...
          if sys.version_info >= (3, 7):
              def kill(self) -> None: ...
              def close(self) -> None: ...
          def is_alive(self) -> bool: ...
          def join(self, timeout: Optional[float] = ...) -> None: ...
      

    2,类的参数

    • group None
      target 子进程执行任务的函数
      name 子进程的名字
      args target函数的参数,为一个元组,须有逗号
      kwarg target函数的关键字参数,是一个字典

    3,类的函数

    • 函数名 作用
      start() 启动进程并调用子进程的p.run
      run() 调用target指定的函数
      terminate() 强制终止进程,使用前应杀掉子进程,并释放锁相关内容
      is_alive() 判活
      join() 等待子进程结束,可设置超时值

    4,类的属性

    • 属性
      p.daemon 默认值是False,如果设为True,代表p 为后台运行的守护程序
      p.name 进程的名称
      p.pid 进程的pid
      p.exitcode 进程在运行时为None,-None表示信号N结束了
      p.authkey 进程的身份验证键

    创建进程的两种方式

    1,第一种

    • 在Windows环境下,开启进程必须在__name__ == ‘main’下面

    • from multiprocessing import Process
      import time
      
      
      def task(name):
          print(f'{name} is runing')
          time.sleep(3)
          print(f'{name} is done')
      
      
      if __name__ == '__main__':
          p = Process(target= task, args=('david',))
          p.start()
          print('===主')
      #########################################  
      ===主
      david is runing
      david is done
      
    • p.start(): 只是向操作系统发出一个开辟子进程的信号,然后就执行下一行,这个信号操作系统接收到之后,会从内存中开辟一个子进程空间,然后将主进程所有数据copy加载到子进程,然后调用CPU去执行

    2,第二种

    • 如果继承了Process类,创建进程时,类中方法必须定义成Process类的方法,类似于类的约束,但是如果没有定义成Process类的方法,程序不会报错,但是子进程没有创建成功

    • class MayProcess(Process):
          def __init__(self,name):
              super().__init__()
              self.name = name
      
          def run(self):
              print(f"{self.name}is run")
              time.sleep(2)
              print(f'{self.name} is dong')
      
      
      if __name__ == '__main__':
          p = MayProcess('david')
          p.start()
          print('===主')
      ########################################
      ===主
      davidis run
      david is dong
      

    获取进程的pid

    • pid():内存中存在多个进程,每个进程的pid是唯一的

    • 当进程结束,pid也随之消失

    • # from multiprocessing import Process
      # import time
      # import os
      #
      # def task(name):
      #     print(f'子进程:{os.getpid()}')
      #     print(f'主进程:{os.getppid()}')
      #
      #
      # if __name__ == '__main__':
      #     p = Process(target=task,args=('world',))  # 创建一个进程对象
      #     p.start()
      #     # print('==主开始')
      #     print(f'====主{os.getpid()}')
      ###########################################
      ====主11228
      子进程:5188
      主进程:11228
      

    验证进程之间的空间隔离

    • 可变数据类型

    • 物理隔离:内存不能共享内存你的数据(lock,队列除外)

    • lst = ['david',]
      
      def task():
          lst.append('hello')
          print(f'子进程{lst}')
      
      if __name__ == '__main__':
          p = Process(target=task)  # 创建一个进程对象
          p.start()
          # print('==主开始')
          time.sleep(3)
          print(f'主:{lst}')
      ##################################
      子进程['david', 'hello']
      主:['david']
      
    • 不可变数据类型

    • from multiprocessing import Process
      import os
      import time
      name = 'david'
      
      def task():
          global name
          name = 'hello'
          print(f'子进程{name}')
      
      
      if __name__ == '__main__':
          p = Process(target=task)  # 创建一个进程对象
          p.start()
          print('==主开始')
          time.sleep(3)
          print(f'主:{name}')
      #######################################
      
      
      
      
      

    join

    • join():一种阻塞

    • join():实现子进程结束之后,在执行主进程

    • def task(sec):
          print('is run')
          time.sleep(sec)
          print('is gone')
      
      
      if __name__ == '__main__':
          start_time = time.time()
          # p1 = Process(target=task, args=(1,))
          # p2 = Process(target=task, args=(2,))
          # p3 = Process(target=task, args=(3,))
          # p1.start()
          # p2.start()
          # p3.start()
          # p1.join()
          # p2.join()
          # p3.join()
          lst = [Process(target=task, args=(i,))for i in range(1, 4)]
          for i in lst:
              i.start()
          i.join()
          print(f'{time.time()-start_time}')
      ##############################################
      is run
      is run
      is run
      is gone
      is gone
      is gone
      3.1298749446868896
      
    • def task(sec):
          print('is run')
          time.sleep(sec)
          print('is gone')
      
      
      if __name__ == '__main__':
          start_time = time.time()
          # p1 = Process(target=task, args=(1,))
          # p2 = Process(target=task, args=(2,))
          # p3 = Process(target=task, args=(3,))
          # p1.start()
          # p2.start()
          # p3.start()
          # p1.join()
          # p2.join()
          # p3.join()
          lst = [Process(target=task, args=(i,))for i in range(1, 4)]
          for i in lst:
              i.start()
          for i in lst:
              i.join()
          print(f'{time.time()-start_time}')
      #############################################
      is run
      is run
      is run
      is gone
      is gone
      is gone
      3.1347217559814453
      

    守护进程

    • 守护进程会在主进程代码结束后就终止

    • 守护进程内无法再开启子进程,否则抛出异常

    • # from multiprocessing import Process
      # import time
      #
      # def task(name):
      #     print(f'{name} is running')
      #     time.sleep(2)
      #     print(f'{name} is gone')
      #
      #
      #
      # if __name__ == '__main__':
      #     # 在windows环境下, 开启进程必须在 __name__ == '__main__' 下面
      #     p = Process(target=task,args=('david',))  # 创建一个进程对象
      #     p.daemon = True  # 将p子进程设置成守护进程,只要主进程结束,守护进程马上结束.
      #     p.start()
      #     # p.daemon = True  # 一定要在子进程开启之前设置
      #     time.sleep(1)
      #     print('===主')
      

    8,其他属性

    • # from multiprocessing import Process
      # import time
      #
      # def task(name):
      #     print(f'{name} is running')
      #     time.sleep(2)
      #     print(f'{name} is gone')
      #
      #
      #
      # if __name__ == '__main__':
      #     # 在windows环境下, 开启进程必须在 __name__ == '__main__' 下面
      #     # p = Process(target=task,args=('xx',))  # 创建一个进程对象
      #     p = Process(target=task,args=('xx',),name='alex') 
      #     p.start()
      #     # time.sleep(1)
      #     # p.terminate()  # 杀死子进程  ***
      #     # p.join()  # ***
      #     # time.sleep(0.5)
      #     # print(p.is_alive())   # ***
      #     # print(p.name)
      #     p.name = 'sb'
      #     print(p.name)
      #     print('==主开始')
      

    9,僵尸进程孤儿进程

    1,僵尸进程

    • 基于Unix环境(Linux,macOS)
    • 定义:所有的子进程结束之后,在被主进程回收之前,都会进入僵尸进程状态
    • 主进程需要等待子进程结束之后,主进程才结束
      • 主进程时刻监测子进程的运行状态,当子进程结束之后,一段时间内,将子进程进行回收
    • 为什么主进程不在子进程结束后马上对其回收呢
      • 所有的子进程结束之后,会立马释放掉文件的操作系统,内存的大部分数据,但是会保留一些内容:进程号,结束时间,运行状态,等待主进程检测到,回收
      • 主进程与子进程时异步关系,主进程无法马上捕获子进程什么时候结束
    • 危害:如果父进程不对僵尸进程进行回收(wait,waitpid),产生大量的僵尸进程,这样就会占用内存,占用进程pid号
    • 解决僵尸进程:
      • 父进程产生大量的子进程,但是不回收僵尸进程,这样就造成大量的僵尸进程,占用进程pid,解决方法:就是直接杀死父进程,僵尸进程就变成了孤儿进程,交由init父进程回收

    2,孤儿进程

    • 父进程由于某种原因结束了,但是你的子进程还在运行中,这样你的这些字进程就成了孤儿进程, 你的父进程如果结束了,你的所有孤儿进程就会被init进程的回收,init就变成了你的父进程,对你进行回收
    希望你眼眸有星辰,心中有山海,从此以梦为马,不负韶华
  • 相关阅读:
    phpcms之会员中心主页
    phpcms之文章详情页
    phpcms之文章列表页
    phpcms之友情链接
    phpcms之首页组成(四)
    phpcms之首页组成(二)
    phpcms之首页组成(三)
    phpcms之首页组成调用
    基于JSch的Sftp工具类
    Flex String转Date
  • 原文地址:https://www.cnblogs.com/daviddd/p/12034390.html
Copyright © 2020-2023  润新知