美文网首页
Python的SimpleQueue

Python的SimpleQueue

作者: welder77 | 来源:发表于2022-10-30 18:30 被阅读0次

    Queue是Python标准库中的线程安全的队列(FIFO先进先出)实现, 提供了一个适用于多线程编程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间的信息传递。

    Python 3.7版本开始添加了新功能SimpleQueue,SimpleQueue相比Queue简化了部分高级功能,拥有更好的性能表现。
    在实际应用中,SimpleQueue的相应功能已可以满足大部分日常需求,所以推荐使用。

    以下为SimpleQueue所拥有的功能:

    1. SimpleQueue.qsize()
      返回队列的大致大小。注意,qsize() > 0 不保证后续的 get() 不被阻塞。

    2. SimpleQueue.empty()
      如果队列为空,返回 True ,否则返回 False 。如果 empty() 返回 False ,不保证后续调用的 get() 不被阻塞。

    3. SimpleQueue.put(item, block=True, timeout=None)
      将 item 放入队列。此方法永不阻塞,始终成功(除了潜在的低级错误,例如内存分配失败)。可选参数 block 和 timeout 仅仅是为了保持 Queue.put() 的兼容性而提供,其值被忽略。

    4. SimpleQueue.put_nowait(item)
      相当于 put(item, block=False),为保持与 Queue.put_nowait() 的兼容性而提供。

    5. SimpleQueue.get(block=True, timeout=None)
      从队列中移除并返回一个项目。如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。

    6. SimpleQueue.get_nowait()
      相当于 get(False) 。

    我们下面通过一个生产者消费者模式的案例来解释下SimpleQueue的用法。

    假设我们有两个线程,一个线程专门用来接收CAN工具源源不断接收到的CAN报文(生产者线程),一个专门用来解析接收到CAN报文(消费者线程)。 由于生产者线程产生的CAN报文非常密集,所以有可能导致消费者线程来不及及时处理,所以我们通过队列来做缓存,防止漏帧。

    from queue import SimpleQueue
    import time, threading
    import sys
    
    # 生产者线程
    def product(name):
        global finish_flag  #需要改写变量,需要加上global
        count = 1
        for n in range(100000):    #假设接收到了100000个报文
            sys.stdout.write(f"{name} 产生的帧:{count}\n")  # 打印产生的报文编号
            q.put(f"{name} 产生的帧:{count}")  # 将报文编号存入队列中
            count += 1
        finish_flag = True  #所有任务完成
    
    # 消费者线程
    def consume(name):
        while True:
            sys.stdout.write(f"{name} 获取了:{q.get()}\n")  # 获取队列中的一个报文编号,默认get不加参数,程序会处于阻塞状态,直到队列中有数据。
            if finish_flag and q.empty():   #当生产者线程完成所有任务,同时队列也为空时退出
                break
    
    
    if __name__ == "__main__":
        # 初始化报文的消息队列
        q = SimpleQueue()
        finish_flag = False
        can_rec = threading.Thread(target=product, args=('can工具',))
        can_analysis = threading.Thread(target=consume, args=('can解析器',))
    
    
        # 开启线程,并等待其执行完毕。
        t1=time.time()
        can_rec.start()
        can_analysis.start()
        can_rec.join()
        can_analysis.join()
        print(time.time()-t1)
    
    

    总结,日常应用中,对于有密集数据接收的情况,比如CAN, Lin报文,接口数据都可以使用Queue做缓存来防止数据丢失。
    Queue和SimpleQueue因为其线程安全的特性,对于线程的读写是非常友好的,也不需要担心线程间的干扰。
    但使用时也需要注意,一旦使用了队列,其原有数据序列间的间隔是无法保存的,比如CAN报文的周期是无法通过队列进行还原的,所以通常存入数据序列的数据我们会为其加上时间戳,以记录其原有时序。

    相关文章

      网友评论

          本文标题:Python的SimpleQueue

          本文链接:https://www.haomeiwen.com/subject/jcvctdtx.html