zoukankan      html  css  js  c++  java
  • 生产者、消费者模型---Queue类

    Queue队列在几乎每种编程语言都会有,python的列表隐藏的一个特点就是一个后进先出(LIFO)队列。而本文所讨论的Queue是python标准库queue中的一个类。它的原理与列表相似,但是先进先出(FIFO)队列。而内部实现更为完善,有很好的数据保护机制和较高的稳定性。

    Queue队列在编程中的实际应用:进程中的通信

           假如两个进程需要互通数据,怎么做?用全局变量,然后在进程中通过global关键字引入全局变量?那么问题是,怎么控制时间效应问题,即什么时候获取、传送变量?如何保证数据的安全性?显然这种方案不是很恰当。python为实现进程的通信提出了几种机制,本文的Queue就是其中一种。另外还有Value,Pipe,Signal等。

    关于Signal可以看看我之前写的文章:

    python进程间通信--信号Signal

    首先需要介绍Queue的类方法:

    1. put()          将元素塞进队列,当队列满时不阻塞等待

    2. put_nowait()    将元素塞进队列,当队列满时阻塞等待

    3. get()           从队列中取出元素,如果队列为空,阻塞等待

    4.get_nowait()     从队列中取出元素,如果队列为空,不阻塞等待

    5. full()           判断队列是否为已经满

    6. empty()        判断队列是否为空

    7. qsize()         获取队列的元素个数

    8. task_done()     当队列中的任务完成之后会自动调用task_done通知Queue,并对join()方法其作用

    9. join()          阻塞等待直到所有的队列任务完成(被取出)

    几个关键方法的详细解析

    1. put(item,block = True,timeout = None)

    将数据放进队列,item为需要塞进的元素,可以是基本数据类型变量,也可以是函数。block默认为True,即当Queue已经满时,阻塞等待(阻塞是同步的,会影响下面的程序运行)。timeout为阻塞等待超时时间,单位为秒,当超过指定时间,退出阻塞,同时报出Queue.Full错误。

    2. put_nowait(item)

    基本用法与put相同。当队列为满时,不阻塞等待,相当于put(item,block = False)

    3. get(block= True ,timeout = None)

        获取队列元素,block默认为True,当队列为空时,阻塞等待。timeout为超时时间,单位为秒,当超过指定时间,退出等待。

    一、Queue类方法基本使用(为了方便调用接口,在Queue基础上再进行了一次封装):

    from queue import Queue
    
    class MyQueue():             #自定义一个MyQueue类
        def __init__(self,size=3):
            self.max_size = size
            self.queue = Queue(size)
    
      #put()方法可以传入数值
        # item1 = 2
        # item2 = 3
        # item3 = 3
        # queue.put(item1)
        # queue.put(item2)
        # queue.put(item3)
    
        # 超过长度的内容
        # item4 = 5
        # queue.put_nowait(item4)
    
      #put()方法也可以传入函数
        def _print_num(self,n):
            num = n
            return num
    
        def write_queue(self):
            for n in range(4):
                try:
                  self.queue.put_nowait(self._print_num(n))  #如果队列已经满了,会报出Full错误
                except:
                    print('队列已经满了,无法添加内容')
    
    
        def print_queue_length(self):
           print('队列的长度是:',self.queue.qsize())
    
        def get_queue(self):
            if self.queue.empty() is False:
                queue_size = self.queue.qsize()
                n = 1
                for i in range(queue_size):
                    if n > queue_size:
                        print('队列已经空了')
                    value = self.queue.get()
                    print('队列第%s个值是:%s'%(n,value))
                    n += 1
            else:
              print('队列已经空了')
    
    
    #实例化代码
    myqueue = MyQueue()
    myqueue.write_queue()
    myqueue.print_queue_length()
    myqueue.get_queue()

    运行结果

    二、多进程间通信:

    from multiprocessing import Process,Manager
    
    #将数据装进队列
    def put_msg(q,lock):
        lock.acquire()
        for i in range(3):
            print('Put the %s into the queue'%i)
            q.put(i)
        lock.release()
    
    
    #将数据取出
    def get_msg(q):
        while True:
            if not q.empty():
                value = q.get(False)
                print('Get the %s from the queue'%value)
            else:
                break
    
    
    if __name__ == '__main__':
        manager = Manager()
        q = manager.Queue(5)    #队列长度设为5
        lock = manager.Lock()
        processes = []
        process1 = Process(target=put_msg,args=(q,lock))
        process2 = Process(target=get_msg,args=(q,))
    
        processes.append(process1)
        processes.append(process2)
        for p in processes:
            p.start()
            p.join()

    在父进程中创建Queue,传入两个子进程,因为python中父进程无法与子进程进行通信,必须使用Manage来实现。为了只有一个进程在对Queue进行操作,使用Manage的Lock。

    结果:
    Put the 0 into the queue
    Put the 1 into the queue
    Put the 2 into the queue
    Get the 0 from the queue
    Get the 1 from the queue
    Get the 2 from the queue

    解析:

    操作系统中的进程本质上是一个程序在一个数据集上动态执行的过。而进程通常是由程序、数据集和进程控制块组成。

    程序:也就是我们平时在IDE上编写的代码,描述了一个进程的内部运行逻辑和功能;

    数据集:程序执行过程中需要使用到的资源,包括IO资源和基本数据;

    进程控制块:操作系统通过进程控制块来对进程进行控制和管理,记录进程的外部特征和描述进程的执行过程

    为了确保进程的独立性和安全性,操作系统在执行程序的时候会用到一种数据解构--栈。程序和数据的入栈和出栈对应进程的等待执行和正式执行。如此一来,各进程间的数据集是相互隔离的(即使可能在同一个栈中)。要进行进程间的通信或者子进程和父进程间的通信,就必须通过一定的机制。上面谈到到的Queue和Manage正是python中实现进程间通信的其中两种。

    参考文章:

    http://python.jobbole.com/86181/

  • 相关阅读:
    网页中这 10 种字体的运用方式,不会让人觉得 Low
    如何估算文章阅读时长?
    如何养出一个三十几亿身家的儿子
    2018免费的隐私保护工具
    写一份好的产品说明书
    安装 Ubuntu 19.10 选用 zfs 文件系统
    ESXI常用命令
    Harbor ($docker login) Error saving credentials
    Vue中使用matomo进行访问流量统计的实现
    eslint Cannot read property 'range' of null错误
  • 原文地址:https://www.cnblogs.com/thomson-fred/p/10018609.html
Copyright © 2011-2022 走看看