进程学习记录1

跨平台的进程创建模块

1.方法一: 使用 Process 类创建子进程

支持跨平台:windows / linux

multiprocessing 提供了一个 Process 类来代表一个进程对象

from multiprocessing import Process
import os


def download(fileName, type, **kwargs):
    print('开启进程下载,进程号为:%s' % os.getpid())
    if kwargs['device'] == 'iphoneX':
        path = "http://www.baidu.com/iphoneX"
        # print("下载路径为:%s/%s.%s" % (path, fileName, type))
        print("下载路径为: %s/%s.%s" % (path, fileName, type))

if __name__ == '__main__':
    # 1.创建和启动
    # 创建格式: p = Process(target=函数名)   为某个功能函数创建多进程
    # 注意函数名后面不可以加括号
    p = Process(target=download, name="下载进程", args=("logo", "png"), kwargs={"device":"iphoneX"})
    
    # 2.对子进程的操作:一定要放在p.start()前面,否则可能会在执行子进程的操作时,子进程就有可能已经被释放掉了。
    # 打印别名
    print(p.name)
    
    # 启动子进程,对象不start的话子进程的函数就不会执行。
    p.start()
    print("下载完成")
    
    '''
    def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
    参数分析
    group: 分组(基本不用)
    target: 表示这个进程实例所调用的对象
    name: 给进程起一个别名
    args: 参数,表示非关键字收集参数,使用元组收集
    kwargs: 表示关键字收集参数,使用字典收集
    '''

上述代码返回值:

下载进程
下载完成
开启进程下载,进程号为:17344
下载路径为: http://www.baidu.com/iphoneX/logo.png

1.1 代码拓展

上述代码还有个问题:

因子进程的文件还没有下载完成,就已经print("下载完成")。
所以需要主进程等待子进程执行完成之后,主进程才接着往下执行


1.1.1 阻塞主进程和子进程的生命状态

使用阻塞解决上述问题 join()

使用 join() 阻塞主进程执行

应用场景:更新系统时,会先下载安装包,会使用多进程阻塞安装的主进程,等所有安装包都下载完成后,才开始安装软件

拓展:

  • 以下是 join() 的源码

    def join(self, timeout=None):
       pass
    
  • timeout 的参数:主进程设置阻塞时间,不管子进程完成与否,阻塞时间到了之后,主进程都继续执行。

  • p.join(5) 设置阻塞5秒,

  • 注意点:设置阻塞5 秒,如果子进程在5秒以内执行完毕了,主进程会继续执行剩下的内容,而不会死等到5秒才执行剩下的内容

进程的生命状态 is_alive()

  • 格式:p.is_alive()
  • 返回值:
    • True: 子进程活着
    • False: 子进程结束

1.1.2 终止子进程

  • 格式:p.terminate()

  • 作用:不管进程是否完成,立即终止

  • 通常 join()is_alive() 和 **terminate() **这三个方法连用,代码如下

    • 代码示例
    p.join(4)
    if p.is_alive() == Ture:
        p.terminate()
    

2. 方法二:定义类创建子进程(推荐使用这种方法)

  • 可以使用定义类的方式,并继承Process类,来创建子进程
  • 实例化这个类,就相当于实例化了一个进程对象
from multiprocessing import Process
import os
import time


# 定义一个类,继承 Process 类
class ManualProcess(Process):
    def __init__(self,interval):
        # 继承 Process 类的初始化方法,提供传参
        Process.__init__(self)
        self.interval = interval
    
    
    # 重写 Process 类中的 run() 方法,run()方法为 Process类的中执行子进程中函数的方法
    # 这块是核心
    def run(self):
        t_start = time.time()
        print('子进程(%s)开始执行,父进程为(%s)' % (os.getpid(), os.getppid()))
        time.sleep(self.interval)
        t_stop = time.time()
        print('(%s)进程执行结束,耗时%.2f秒' % (os.getpid(), (t_stop - t_start)))

if __name__ == '__main__':
    t_start = time.time()
    print('当前程序的进程号为:%s ' % os.getpid())
    p = ManualProcess(interval=2)
    
    # 对于一个不包含target属性的Process类(实例化时,没有给 target 传参),如果执行了start()方法
    # 表示子进程就会运行类中的run()方法
    p.start()
    
    p.join()
    t_stop = time.time()
    print('(%s)进程执行结束,耗时%.2f秒' % (os.getpid(),(t_stop - t_start)))

代码返回值如下:

当前程序的进程号为:14040
子进程(4240)开始执行,父进程为(14040)
(4240)进程执行结束,耗时2.01秒
(14040)进程执行结束,耗时2.55秒

下图为继承Process类创建子进程的方法注意要点

  • 图中的 (1)(2)(3)(4)红色区域表示是必须要写的部分,类似框架的意思
  • 蓝色区域是自定义功能的区域,以便后期做代码扩展或重新写功能
进程学习记录1

3. 代码练习

  • 需求:

    • 键盘输入一个整数,分别开启两个进程来计算这个输的累加和与阶乘
    • 第一个进程使用系统提供给我们的类
    • 第二个进程需要自己定义
    from multiprocessing import Process
    import time
    import os
    
    # 定义阶乘进程类
    class FactorialClass(Process):
      def __init__(self,interval):
            # 继承Process类的初始化方法
          Process.__init__(self)
          self.interval = interval
          
      # 定义阶乘方法
      def run(self):
          t_start = time.time()
          res = 1
          for i in range(1, self.interval+1):
              res *= i
          t_stop = time.time()
          print('阶乘子进程(%s)执行完毕,累计耗时 %.7f 秒' % (res, t_stop - t_start))
          print('%d的阶乘为%d' % (self.interval, res))
          return res  
    
    # 累加功能
    def accumulate(interval):
      t_start = time.time()
      res = 0
      for i in range(1,interval+1):
          res += i
      t_stop = time.time()
      print('累加子进程(%s)执行完毕,累计耗时 %.7f 秒' % (res, t_stop-t_start))
      print('%d的累加和为%d' % (interval, res))
      return res
      
    # 程序入口
    def main():
      try:
          interval = int(input("请输入一个整数:"))
            #定义程序开始时间
          t_start = time.time()
            
          # 实例化Process类
          p1 = Process(target=accumulate,args=(interval,))
          # 实例化自定义类
          p2 = FactorialClass(interval)
          
            # 开启 p1和p2 进程
          p1.start()
          p2.start()
          
            # 设置阻塞
          p1.join()
          p2.join()
            
            # 定义程序结束时间
          t_stop = time.time()
          print('主进程(%s)执行完毕,累计耗时 %.7f 秒' % (os.getpid(), t_stop-t_start))
    
      except Exception as f:
          print("输入有误,结束")
    
      
    if __name__ == '__main__':
      main()