• 多任务--线程


    进程

    一、概念

    二、进程的创建和操作

    三、进程通信--Queue

    四、进程池

    五、进程与线程区别

    六、案例

    回到顶部

    一、概念

    1.概念

      进程: 通俗理解一个运行的程序或者软件,进程是操作系统资源分配的基本单位。

      注意: 一个程序至少有一个进程,一个进程至少有一个线程,多进程可以完成多任务.

    2.进程的执行状态

      工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态

     

    • 就绪态:运行的条件都已经慢去,正在等在cpu执行
    • 执行态:cpu正在执行其功能
    • 等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态

    二、进程的创建和操作

    1.进程的创建

      创建进程 : pro = multiprocessing.Process(target=入口, args=(), kwargs={})

      开始执行 : pro.start()

    2.进程的操作

      pro.join() 一直等待 死等

    ​       pro.join(2) 阻塞等待子进程2秒 如果子进程没有终止那主进程就直接往下执行

    ​     pro.terminate() 终止子进程

    ​     pro.is_alive() 判断子进程状态

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    import multiprocessing
    import time
    import os
    
    def pro_info(info, data):
        """子进程 运行的代码"""
        for i in range(30):
            print("这是子进程 info=%s data=%s PID=%s PPID=%s" % (info,data,os.getpid(),os.getppid()))
            time.sleep(1)
    
    def main():
        """单进程 单线程模式 主进程"""
        # 创建子进程
        pro = multiprocessing.Process(target=pro_info, args=("今天天气不错",), kwargs={"data":"50"}, name="陈特特")
        # 创建 启动子进程
        pro.start()
    
        # 主进程阻塞等待子进程 2秒 / 如果能等到子进程退出 回收子进程的资源
        pro.join(2)
        print("获取子进程的pid = %s name = %s" % (pro.pid,pro.name))
        print("===============================")
    
        # 判断子进程是否存活
        print(pro.is_alive())
    
        # # 终止子进程 像操作系统发出一个 终止子进程的信号 存在延迟 不要立即判断子进程的状态
        # pro.terminate()
        # 判断子进程是否存活
        print(pro.is_alive())
        print("===============================")
    
        for i in range(3):
            # 查看当前所在进程的PID
            print("这是主进程 PID=%s" % os.getpid())
            time.sleep(1)
    
    if __name__ == '__main__':
        main()
    示例代码

    三、进程通信--Queue

      1.使用队列Queue的原因

        原因: 进程间不共享全局资源

        Queue 是一种进程间通信的方式, 先进先出

      2.使用方法

    • 创建 队列对象 = multiprocessing.Queue(长度)
    • 放 队列对象.put(数据)
    • 取 数据 = 队列对象.get()
    • 判断空 队列对象.empty()
    • 判断满 队列对象.full()
    • 数量 队列对象.qsize()
      import multiprocessing
      import time
      
      
      def proc_func(q):
          """子进程入口"""
          while True:
              time.sleep(3)
              # 判断空
              if q.empty():
                  print("队列中已经没有了 稍后再来")
                  time.sleep(3)
              # 从队列中取出数据
              data = q.get()
              print("从队列中取出了数据%s" % data)
      
      def main():
          pass
          # 1 创建出来 主进程和子进程通信所需的 队列对象
          q = multiprocessing.Queue(3)
      
          # 2 创建子进程 
          pro = multiprocessing.Process(target=proc_func, args=(q,))
          pro.start()
      
          while True:
              # 3 接收输入 放入队列中
              data = input(":")
              # 判断队列满 
              if q.full():
                  print("慢点输入已经满了 马上溢出了")
                  time.sleep(1)
              # 向队列中放入数据
              q.put(data)
      
      if __name__ == '__main__':
          main()
      示例

    四、进程池

    1.工作模式

      模式提前创建一批进程, 重复利用已经空闲的进程执行 多任务

      优点 :  节约了 大量进程的创建/销毁的开销, 提高任务的响应速度

    2.添加任务两种方式

      同步方式 : 会阻塞等待添加任务的执行完成后才会继续往下执行

    ​     异步方式 :只添加任务 不会等待任务执行完成

    3.使用步骤和注意事项   

    1 创建进程池  进程池对象 = multiprocessing.Pool(工作进程的数量)        
    
    2 添加任务      
    
        同步  进程池对象.apply(入口)  添加任务并等待任务执行完成
    
        异步  进程池对象.apply_async(入口)  只添加任务 不等待任务完成
    
    3 关闭进程池
    
        进程池对象.close()  不允许添加新任务
    
    4 等待所有任务执行完成
    
        进程池对象.join()

      注意:进程池之间的进程通信不能使用multiprocessing.Queue 而应该使用 multiprocessing.Manager().Queue

    五、进程与线程区别

      1.区别   

    • 进程之间不共享全局变量
    • 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法: 互斥锁或者线程同步
    • 创建进程的资源开销要比创建线程的资源开销要大
    • 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
    • 线程不能够独立执行,必须依存在进程中
    • 多进程开发比单进程多线程开发稳定性要强

      2.优缺点    

      多进程:

        • 优点:可以用多核
        • 缺点:资源开销大

      多线程:

        • 优点:资源开销小
        • 缺点:不能使用多核

      3.功能对比

      • 进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
      • 线程,能够完成多任务,比如 一个QQ中的多个聊天窗口

      4.定义对比

      • 进程是系统进行资源分配基本单位,每启动一个进程操作系统都需要为其分配运行资源。
      • 线程是运行程序中的一个执行分支,是CPU调度基本单位。
      • 总结:进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位

    六、案例

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    import multiprocessing
    import os
    
    def copy_file(src_path, dest_path, file):
        """从源目录下 将file对应的文件数据读取并且写到目的目录下 file文件中"""
        # 1.打开源目录下的文件用以读
        src_file = open(src_path + "/" + file, "rb")
        print(dest_path + "/" + file)
    
        # 2.打目的目录下的文件用以写
        dest_file = open(dest_path + "/" + file, "wb")
    
        # 3.一遍从源文件中读取数据 写入目的文件中
        while True:
            file_data = src_file.read(1024)
            if not file_data:
                print("%s文件拷贝完成" % file)
                break
            dest_file.write(file_data)
        # 4.完成后  关闭源文件 关闭目的文件中
        src_file.close()
        dest_file.close()
    
    def main():
        # 1.用户输入备份的目录
        source_path = input("请输入要备份的目录:")
    
        # 2.根据源目录创建一个目的目录 源目录-备份
        dest_path = source_path + "-备份"
        os.mkdir(dest_path)
    
        # 3.根据源目录去获取源目录下所有的 文件名称
        file_list = os.listdir(source_path)
        # print(file_list)
    
        # 4.根据每个源文件的名称 读取出每个文件的数据 将数据写入到 目的目录/源文件
        for file in file_list:
            pro = multiprocessing.Process(target=copy_file, args=(source_path, dest_path, file))
            pro.start()
    
    
    if __name__ == '__main__':
        main()
    备份当前目录---多进程
    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:Mr.yang
    import multiprocessing
    import time
    import os
    
    def copy_file(src_path, dest_path, file, q):
        """从源目录下 将file对应的文件数据读取并且写到目的目录下 file文件中"""
        # 1.打开源目录下的文件用以读
        src_file = open(src_path + "/" + file, "rb")
    
        # 2.打目的目录下的文件用以写
        dest_file = open(dest_path + "/" + file, "wb")
    
        # 3.一遍从源文件中读取数据 写入目的文件中
        while True:
            file_data = src_file.read(1024)
            if not file_data:
                # print("%s文件拷贝完成" % file)
                break
            dest_file.write(file_data)
        # 4.完成后  关闭源文件 关闭目的文件中
        src_file.close()
        dest_file.close()
        # 5.当任务完成后 向队列中添加一个消息 表示完成
        q.put(file)
    
    def main():
        # 1.用户输入备份的目录
        source_path = input("请输入要备份的目录:")
    
        # 2.根据源目录创建一个目的目录 源目录-备份
        dest_path = source_path + "-备份"
        os.mkdir(dest_path)
    
        # 3.根据源目录去获取源目录下所有的 文件名称
        file_list = os.listdir(source_path)
        # print(file_list)
    
        # 4.根据每个源文件的名称 读取出每个文件的数据 将数据写入到 目的目录/源文件
        # 使用进程池处理每个任务
        # 4.0 创建出一个队列 用于进程间通信 不能使用multiprocessing.Queue(10)
        # q = multiprocessing.Queue(10)
        q = multiprocessing.Manager().Queue(10)
    
        # 4.1 创建进程池
        p = multiprocessing.Pool(4)
    
        # 4.2 添加任务到进程池中
        for file in file_list:
            p.apply_async(copy_file,args=(source_path, dest_path, file, q))
        # 4.3 关闭进程池
        p.close()
    
        # 从队列中取出消息
        count = 0
        while True:
            if count == len(file_list):
                break
            q.get()
            count += 1
            print("
    当前进度是%.2f %%" % ((count/len(file_list))*100), end="")
            time.sleep(0.1)
    
        # 4.4 等待进程池所有任务都执行完成
        p.join()
    
    
    if __name__ == '__main__':
        main()
    备份当前目录---进程池
  • 相关阅读:
    阅读计划
    个人介绍
    构建之法阅读笔记04
    结对开发——返回一个整数数组中最大子数组的和 (首尾相接版)
    结对开发——返回一个整数数组中最大子数组的和
    学习进度条(三)
    构建之法阅读笔记03
    结对开发——四则运算(三)
    四则运算——单元测试(测试方法:Right-BICEP )
    学习进度条(二)
  • 原文地址:https://www.cnblogs.com/Mryang123/p/9997738.html
Copyright © 2020-2023  润新知