队列和进程的使用

本文详细介绍了Python中队列Queue的使用,包括FIFO、LIFO和PriorityQueue,并展示了如何在多线程中实现同步。此外,还探讨了进程的概念、状态以及与线程的区别,讲解了如何创建和使用进程,包括Process类的参数和方法。最后,讨论了多进程间的数据通信问题,强调了multiprocessing.Queue在进程通信中的重要性。
摘要由CSDN通过智能技术生成

一、队列的使用

  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)    # 最大只能添加三条数据
      
    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)   # 如果队列已满,则会进入堵塞状态(等待)
      
    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))   # 如果队列为空,则会进入堵塞状态(等待)
      
    4. 判断队列是否满了:Queue.full()

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

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

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

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

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

      # 5. 取队列中的数据量
      print(q.qsize())
      
    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("------等待线程中所有的数据处理完毕再往下执行-----------")
      

      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("------等待线程中所有的数据处理完毕再往下执行-----------")
      

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

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

顾名思义:

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

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

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

    	# 创建一个队列对象
    	q = LifoQueue(3)    # 最大只能添加三条数据
    	q = PriorityQueue()    # 最大可接收数量没有上限
    
  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'))
    
  3. 获取队列中数据的方法:LifoQueue .get(item) / PriorityQueue.get(item)

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

    # LifoQueue 队列
    # 2. 获取队列中数据的方法:get
    q.get()      # ======> 取出来的数据为 111
    q.get()      # ======> 取出来的数据为 222
    q.get()      # ======> 取出来的数据为 333
    
    # 添加第四条数据
    # 参数:block表示是否等待,timeout表示等待时间
     print(q.get(block=False))   # 如果队列为空,则会进入堵塞状态(等待)
    
    # (优先级队列) PriorityQueue
    # 3. 获取队列中数据的方法:get ----元祖第一个值通常来表示优先级,用第一个值来比较优先级
    q.get()      # ======> 取出来的数据为 (4, '222')
    q.get()      # ======> 取出来的数据为 (77, '111')
    q.get()      # ======> 取出来的数据为 (888, '333')
    

二、进程的使用

一 、进程模块的详细使用

  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)
    

    2、name参数: 设置进程名

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

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

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

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

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

    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("----主线程执行结束-----------")
    
  6. 进程方法的使用

    Process类提供了以下方法:

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

    # 启动线程执行
    t1.start()
    t2.start()
    

    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("主进程全部执行完成——————————————————————————")
    

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

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

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

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

    7、getName:获取线程名

  7. 注意点

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

  8. 多进程的数据通信问题

    1. 各个进程之间的数据都是独立的,互不相同
    2. 进程之间进行数据传输,只能使用进程模块中的队列multiprocessing.Queue,使用队列中的Queue 会报错
    3. 每创建一个进程,会有一个默认的线程
      进程是资源分配的基本单位,线程是操作系统任务调动执行的基本单位
    1. multiprocessing.Queue() 和 queue.Queue区别

      1. from multiprocessing import Process, Queue =========》这是进程模块
        multiprocess.Queue 是跨进程通信队列使用
      2. from queue import Queue =========》这是队列模块
        queue.Queue是进程内队列,同一个进行中多个线程之间通信用

    例如:

    a = 0
    
    def work1(q):
        a = q.get()
        for i in range(2000000):
            a += 1
        print("work中的a:", a)
        q.put(a)
    
    
    def work2(q):
        a = q.get()
        for i in range(1000000):
            a += 1
        print("work2中的a:", a)
        q.put(a)
    
    
    def main():
        a = 0
        que = Queue()     # 创建队列对象
        que.put(a)       
        p1 = Process(target=work1, args=(que,))   # 进程1
        p1.start()
        p2 = Process(target=work2, args=(que,))   # 进程1
        p2.start()
        p1.join()
        p2.join()
        a = que.get()
        print("主进程中a:", a)
    
    
    if __name__ == '__main__':
        main()
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值