• 队列和进程的使用


    一、队列的使用

    1. 队列的认识:

      1. Python的Queue模块中提供了同步的、线程安全的队列类,包括:FIFO(先入先出)队列QueueLIFO、(后入先出)队列LifoQueue、优先级队列PriorityQueue,这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步
      2. 队列中数据添加和获取 已经加了锁(所有用队列来存储多线程公用的全局数据,不会出现资源竞争的问题)
    2. 队列的的类型:

      1. (先入先出队列) Queue , 快速使用:from queue import Queue
      2. (后入先出队列)LifoQueue , 快速使用:from queue import LifoQueue
      3. 优先级队列 PriorityQueue , 快速使用:from queue import PriorityQueue
        队列中的元素为元祖类型:(优先级,数据)------- 例如:(99,33333)
    3. 类型一:(先入先出) Queue队列
      顾名思义:先入先出,先进入的数据,先获取出来

      1. 初始化Queue()对象时,若括号中没有指定最大可接收的消息数量,或数量为负值,代表可接受的消息数量没有上限

        例如:q=Queue(3) 表示最大可接收数量为3
        例如:q=Queue(0) 表示最大可接收数量没有上限

        	# 创建一个队列对象
        	q = Queue(3)    # 最大只能添加三条数据
        
        • 1
        • 2
      2. 往队列中添加数据的方法:Queue.put(item)

        语法: put(self, item, block=True, timeout=None)
        参数1 ———》 item: 数据
        参数2 ———》 block: 如果队列已满是否等待;
        参数3 ———》 timeout: 等待的超时时间,超时后报错

        # 1. 往队列中添加数据的方法: put
        q.put('111')
        q.put('222')
        q.put('333')
        
        # 添加第四条数据
        # 参数:block表示是否等待,timeout表示等待时间
         q.put('444',block=False,timeout=3)   # 如果队列已满,则会进入堵塞状态(等待)
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
      3. 获取队列中数据的方法:Queue.get()

        语法: get(self, item, block=True, timeout=None)
        参数1 ———》 item: 数据
        参数2 ———》 block: 如果队列已满是否等待;
        参数3 ———》 timeout: 等待的超时时间,超时后报错

        # 2. 获取队列中数据的方法:get
        q.get()      # ======> 取出来的数据为 111
        q.get()      # ======> 取出来的数据为 222
        q.get()      # ======> 取出来的数据为 333
        
        # 添加第四条数据
        # 参数:block表示是否等待,timeout表示等待时间
         print(q.get(block=False))   # 如果队列为空,则会进入堵塞状态(等待)
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
      4. 判断队列是否满了:Queue.full()

        语法: 如果队列满了,返回True, 反之False

        # 3. full:判断队列是否已满
        print(q.full())   # 满的就是True  ,反之
        
        • 1
        • 2
      5. 判断队列是否为空:Queue.empty()

        语法: 如果队列为空,返回True, 反之False

        # 4. empty:判断队列是否为空
        print(q.empty())  # 为空的就是True  ,反之
        
        • 1
        • 2
      6. 返回队列消息数量:Queue.qsize()

        语法:返回当前队列包含的消息数量

        # 5. 取队列中的数据量
        print(q.qsize())
        
        • 1
        • 2
      7. Queue.task_done()

        语法:在完成一项工作之后,使用Queue.task_done()方法可以向队列发送一个信号,表示该任务执行完毕

      8. Queue.join()

        1. 语法:实际上意味着等到队列中所有的任务(数据)执行完毕之后,再往下,否则一直等待
        2. 注意点:join()是判断的依据,不单单指的是队列中没有数据,数据get出去之后,要使用task_done()向队列发送一个信号,表示该任务执行(数据使用)完毕
        3. 队列中task_done方法和join 是相互配合使用的,缺一不可

        1.在使用线程实现子线程执行完后在执行主线程

        # 初始化对象
        q = Queue()
        
        for i in range(15):
            q.put('数据{}'.format(i))   # 添加队列数据
        
        def work(data):
            """线程执行的工作函数"""
            for i in range(5):
                time.sleep(random.randint(1, 4))   # 随机等待时间
            print("数据data:{}处理完毕".format(data))
        
        def main():
            """使用线程等待的方法"""
            ts =[]
        
            for i in range(10):
                data = q.get()
                t1 = Thread(target=work, args=(data,))
                t1.start()
                ts.append(t1)
        
            for i in ts:
                i.join()
                
            print("------等待线程中所有的数据处理完毕再往下执行-----------")
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26

        2.使用队列来实现子线程执行完后在执行主线程

        # 初始化对象
        q = Queue()
        
        for i in range(15):
            q.put('数据{}'.format(i))   # 添加队列数据
        
        def work(data):
            """线程执行的工作函数"""
            for i in range(5):
                time.sleep(random.randint(1, 4))   # 随机等待时间
            print("数据data:{}处理完毕".format(data))
            # 给队列发送一个信号,已经处理好了
            q.task_done()
        
        def main():
            """使用队列等待的方法"""
            for i in range(10):
                data = q.get()   # 获取数据
                t1 = Thread(target=work, args=(data,))   # 设置线程
                t1.start()   # 启动线程
        
            # 等待队列中所有的任务执行完毕(数据处理完毕)
            q.join()
            print("------等待线程中所有的数据处理完毕再往下执行-----------")
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24

    4.类型二和三:(后入先出) LifoQueue 队列 和 (优先级队列) PriorityQueue

    三种类型的队列,Queue队列、 LifoQueue 队列 、PriorityQueue 方法都是一样,唯一区别是数据的的取出不一样

    顾名思义:

    后入先出,后面进入的数据,先获取出来
    优先级队,根据排序优先级,先获取出来

    1. 初始化对象时,若括号中没有指定最大可接收的消息数量,或数量为负值,代表可接受的消息数量没有上限

      例如:q=LifoQueue (3) 表示最大可接收数量为3
      例如:q=LifoQueue(0) 表示最大可接收数量没有上限

      	# 创建一个队列对象
      	q = LifoQueue(3)    # 最大只能添加三条数据
      	q = PriorityQueue()    # 最大可接收数量没有上限
      
      • 1
      • 2
      • 3
    2. 往队列中添加数据的方法:LifoQueue .put(item) / PriorityQueue.put(item)

      语法: put(self, item, block=True, timeout=None)
      参数1 ———》 item: 数据
      参数2 ———》 block: 如果队列已满是否等待;
      参数3 ———》 timeout: 等待的超时时间,超时后报错

      # LifoQueue 队列
      # 1. 往队列中添加数据的方法: put
      q.put('111')
      q.put('222')
      q.put('333')
      
      # 添加第四条数据
      # 参数:block表示是否等待,timeout表示等待时间
       q.put('444',block=False,timeout=3)   # 如果队列已满,则会进入堵塞状态(等待)
      
      # PriorityQueue队列
      # 1. 往队列中添加数据的方法: put
      q.put((77,'111'))      # 队列中的元素为元祖类型)
      q.put((4,'222'))
      q.put((888,'333'))
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    3. 获取队列中数据的方法:LifoQueue .get(item) / PriorityQueue.get(item)

      语法: get(self, item, block=True, timeout=None)
      参数1 ———》 item: 数据
      参数2 ———》 block: 如果队列已满是否等待;
      参数3 ———》 timeout: 等待的超时时间,超时后报错

      # 2. 获取队列中数据的方法:get
      q.get()      # ======> 取出来的数据为 111
      q.get()      # ======> 取出来的数据为 222
      q.get()      # ======> 取出来的数据为 333
      
      # 添加第四条数据
      # 参数:block表示是否等待,timeout表示等待时间
       print(q.get(block=False))   # 如果队列为空,则会进入堵塞状态(等待)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    二、进程的使用

    一 、进程模块的详细使用

    1. 什么是进程:

      一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元

    2. 进程的状态

      1. 工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态
      2. 就绪状态:运行的条件都已经满足了,随时可以给操作系统调度执行
      3. 执行状态:cpu正在执行其功能
      4. 等待状态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态
    3. 进程和线程有什么区别

      1. 从功能来说:
        进程是能够能够完成多任务,比如 在一台电脑上能够同时运行多个软件
        线程是能够完成多任务,比如 一个QQ中的多个聊天窗口
      2. 从定义上来说:
        一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源,在操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),故对它的调度所付出的开销就会小得多, 能更高效的提高系统内多个程序间并发执行的程度
    4. 创建进程对象: multiprocessing .Process (target=任务函数)

      其中参数target指定线程执行的任务 (函数)

    5. 进程参数的使用

      内置的进程的模块是:multiprocessing 模块里的 Process 类

      multiprocessing模块就是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情
      快速使用:from multiprocessing import Process

      Process 类有以下参数:

      1、target参数: 指定任务函数

      import time
      from multiprocessing import Process
      
      
      def func1():
          for i in range(5):
              print("-正在做事情1------")
              time.sleep(1)
              
      # 创建一个线程对象
      aa = Process(target=func1)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      2、name参数: 设置进程名

      	# 创建一个进程对象
      	aa = Process(target=func1,name="henry")
      
      • 1
      • 2

      3.、args参数: 给任务函数传参(参数传递的是元祖类型)

      	def func1(aa):
          for i in range(5):
              print("---{}---正在做事情1------".format(aa)
              time.sleep(1)
              
      	# 创建一个进程对象
      	aa = Process(target=func1,args=('张三',))
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      4、kwargs参数:给任务函数传参(参数传递的是字典类型)

      	def func1(aa):
          for i in range(5):
              print("---{}---正在做事情1------".format(aa)
              time.sleep(1)
              
      	# 创建一个进程对象
      	aa = Process(target=func1,kwargs={'aa': "李四"})
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      5、daemon参数:设置是否作为守护进程(bool值)

      1. 设置子进程守护主进程执行(主进程结束,守护进程自动结束)
      2. 如果没有设置守护进程,主进程跑完,子进程没有跑完,还会继续跑下去,不会有影响
      3. 如果设置了守护进程,主进程跑完,子进程没有跑完,当前进程全部结束(包括子进程,不管是否跑完)
      4. 如果多个子进程,一个设置了守护进程,一个没有设置守护进程,主进程结束,子进程还会继续跑下去,不会有影响
      def func1(aa):
         for i in range(5):
             print("---{}---正在做事情1------".format(aa))
             # print("---正在做事情1------")
             time.sleep(1)
      
      
      def func2(aa):
         for i in range(6):
             print("----{}--正在做事情2------".format(aa))
             time.sleep(1)
         
      # 创建一个进程对象       
      t1 = Process(target=func1, args=('张三',),daemon=True)      # 设置守护进程 
      t2 = Process(target=func2, kwargs={'aa': "李四"},daemon=True)       # 设置守护进程
      
      # 启动进程执行
      t1.start()
      t2.start()
      
      time.sleep(2)
      print("----主线程执行结束-----------")
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
    6. 进程方法的使用

      Process类提供了以下方法:

      1、start()方法: 启动进程执行

      # 启动线程执行
      t1.start()
      t2.start()
      
      • 1
      • 2
      • 3

      2、join([time]): 设置主进程等待的时间

      1. 设置主进程会等待time秒后再往下执行,不设置time,则默认为子进程结束,多个子进程之设置的值会叠加
      2. 多个子进程同时使用join设置的时间会叠加
      def func2():
          for i in range(6):
              print("------正在做事情2------")
              time.sleep(1)
      
      # 创建一个进程对象
      t1 = Process(target=func2)     # 子进程t1
      
      # # 子进程t1启动执行
      t1.start()
      
      # 主进程等待时间
      t1.join()    # 让主进程等待t1执行完,再往下执行
      
      # 主进程等待子线程执行完
      for i in range(10):
      	print("主进程全部执行完成——————————————————————————")
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

      3、run方法 :进程接收到的任务函数,最终是在run方法里面执行的(进程执行的任务)

      4、isDaemon: 判断是否为守护线程

      5、isAlive: 判断线程支持存活(处于执行状态)

      6、is_alive:判断线程支持存活(处于执行状态)

      7、getName:获取线程名

    7. 注意点

      使用多进程时,要确保程序的入口在if name == ‘main’:中

  • 相关阅读:
    MybatisPlus通用枚举
    windows下python opencv ffmpeg读取摄像头实现rtsp推流 拉流
    android源码学习-android异常处理机制
    BUUCTF Basic 解题记录--BUU XXE COURSE
    FreeSWITCH容器化问题之rtp端口占用
    Word修订内容批量标红
    ctf路径字典
    ExtJS 数据处理-Validations(验证器)
    rpc理解
    Redis知识点总结-钊兵的笔记
  • 原文地址:https://blog.csdn.net/qq_40236497/article/details/125505957