线程queue介绍

Queue的种类:

    • FIFO

 Queue.Queue(maxsize=0)

FIFO即First in First Out,先进先出。Queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是个整数,指明了队列中能存放的数据个数的上限。一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。

示例:

import queue

q = queue.Queue()
q.put(1)
q.put(2)
q.put(3) print(q.get())
print(q.get())
print(q.get())

输出: 

1
2
3
    •  LIFO

Queue.LifoQueue(maxsize=0)

LIFO即Last in First Out,后进先出。与栈的类似,使用也很简单,maxsize用法同上

示例:

import queue

q = queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3) print(q.get())
print(q.get())
print(q.get())

   输出:   

3
2
1
    • priority

class Queue.PriorityQueue(maxsize=0)

构造一个优先队列。maxsize用法同上。

示例:

import queue

q =queue.PriorityQueue(3)

q.put((2,'aaron'))
q.put((-1,'jim'))
q.put((5,'jack')) print(q.get())
print(q.get())
print(q.get())

  输出:  

(-1, 'jim')
(2, 'aaron')
(5, 'jack')

基本方法:

   Queue.Queue(maxsize=0)   FIFO, 如果maxsize小于1就表示队列长度无限
       Queue.LifoQueue(maxsize=0)   LIFO, 如果maxsize小于1就表示队列长度无限
       Queue.qsize()   返回队列的大小 
       Queue.empty()   如果队列为空,返回True,反之False 
       Queue.full()   如果队列满了,返回True,反之False
       Queue.get([block[, timeout]])   读队列,timeout等待时间 
       Queue.put(item, [block[, timeout]])   写队列,timeout等待时间 
       Queue.queue.clear()   清空队列

其他: 

task_done()

意味着之前入队的一个任务已经完成。由队列的消费者线程调用。每一个get()调用得到一个任务,接下来的task_done()调用告诉队列该任务已经处理完毕。

如果当前一个join()正在阻塞,它将在队列中的所有任务都处理完时恢复执行(即每一个由put()调用入队的任务都有一个对应的task_done()调用)。

join()

阻塞调用线程,直到队列中的所有任务被处理掉。

只要有数据被加入队列,未完成的任务数就会增加。当消费者线程调用task_done()(意味着有消费者取得任务并完成任务),未完成的任务数就会减少。当未完成的任务数降到0,join()解除阻塞。

生产者消费者模型

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

为什么要使用生产者和消费者模式

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

什么是生产者消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

  生产者消费者简单实例
import threading
import queue def producer():
for i in range(10):
q.put("骨头 %s" % i ) print("开始等待所有的骨头被取走...")
q.join() #等待所有任务完成
print("所有的骨头被取完了...") def consumer(n): while q.qsize() >0: print("%s 取到" %n , q.get())
q.task_done() #告知这个任务执行完了 q = queue.Queue()
p = threading.Thread(target=producer,)
p.start()
c1 = consumer("李闯")

注意:

  • 如果没有q.task_done()的存在,就不会通知线程队列,生产者就会一直阻塞下去。
  • 如果没有q.join()的存在,生产者就不会等待消费者,它会自行结束。
  • q.task_done()方法和q.join()方法的存在,实现了生产者与消费者的同步机制。
import time,random
import queue,threading
q = queue.Queue()
def Producer(name):
count = 0
while count <20:
time.sleep(random.randrange(3))
q.put(count)
print('Producer %s has produced %s baozi..' %(name, count))
count +=1
def Consumer(name):
count = 0
while count <20:
time.sleep(random.randrange(4))
if not q.empty():
data = q.get()
print(data)
print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' %(name, data))
else:
print("-----no baozi anymore----")
count +=1
p1 = threading.Thread(target=Producer, args=('A',))
c1 = threading.Thread(target=Consumer, args=('B',))
p1.start()
c1.start()

这个实例,充分体现了线程队列在生产者消费者模型中,是如何解决生产者与消费者的强耦合的问题。

线程queue使用注意事项

1. 阻塞模式

import queue

q = queue.Queue(10)  #创建一个队列

......
for i in range(10):
q.put('A')
time.sleep(0.5)

这是一段极其简单的代码(另有两个线程也在操作队列q),我期望每隔0.5秒写一个'A'到队列中,但总是不能如愿:间隔时间有时会远远超过0.5秒。原来,Queue.put()默认有 block = True 和 timeou 两个参数。当  block = True 时,写入是阻塞式的,阻塞时间由 timeou  确定。当队列q被(其他线程)写满后,这段代码就会阻塞,直至其他线程取走数据。Queue.put()方法加上 block=False 的参数,即可解决这个隐蔽的问题。但要注意,非阻塞方式写队列,当队列满时会抛出 exception Queue.Full 的异常。

2. 无法捕获 exception Queue.Empty 的异常

while True:
......
try:
data = q.get()
except Queue.Empty:
break

本意是用队列为空时,退出循环,但实际运行起来,却陷入了死循环。这个问题和上面有点类似:Queue.get()默认的也是阻塞方式读取数据,队列为空时,不会抛出 except Queue.Empty ,而是进入阻塞直至超时。 给get方法的参数block=False 的参数,问题迎刃而解。

python之线程queue的更多相关文章

  1. python开发线程:死锁和递归锁&信号量&定时器&线程queue&事件evevt

    一 死锁现象与递归锁 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将 ...

  2. 孤荷凌寒自学python第四十三天python 的线程同步之Queue对象

     孤荷凌寒自学python第四十三天python的线程同步之Queue对象 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) Queue对象是直接操作队列池的对象,队列中可以存放多种对象,当然也 ...

  3. Python 36 死锁现象和递归锁、信号量、Event事件、线程queue

    一:死锁现象和递归锁 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远 ...

  4. Python之路(第四十五篇)线程Event事件、 条件Condition、定时器Timer、线程queue

    一.事件Event Event(事件):事件处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True,那么 ...

  5. python 之 并发编程(进程池与线程池、同步异步阻塞非阻塞、线程queue)

    9.11 进程池与线程池 池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务 池子内什么时候装进程:并发的任务属于计算密集型 池子内什么时候装线程:并发的任务属于I ...

  6. python并发编程之线程(二):死锁和递归锁&信号量&定时器&线程queue&事件evevt

    一 死锁现象与递归锁 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将 ...

  7. python 并发编程 多线程 线程queue

    线程queue 线程之间已经是共享数据的,为什么还使用线程queue? 线程需要自己加锁,线程queue帮我们处理好加锁的问题 有三种不同的用法 第一种方法: class queue.Queue(ma ...

  8. Python之网路编程之死锁,递归锁,信号量,Event事件,线程Queue

    一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统 ...

  9. Python并发编程06 /阻塞、异步调用/同步调用、异步回调函数、线程queue、事件event、协程

    Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件event.协程 目录 Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件 ...

随机推荐

  1. jzoj5925

    tj:這道題題解有錯 水法ac代碼如下: #include<bits/stdc++.h> using namespace std; typedef long long ll; ll t,n ...

  2. DCL,即Double Check Lock,中卫双重检查锁定。

    DCL,即Double Check Lock,中卫双重检查锁定. [Java并发编程]之十六:深入Java内存模型——happen-before规则及其对DCL的分析(含代码) 关于单例.关于DCL: ...

  3. class字节码结构(四)(方法集合的结构)

    <Java虚拟机原理图解>1.5. class文件中的方法表集合--method方法在class文件中是怎样组织的 一个类有多个方法,所以方法肯定是一个集合. 目标是: 1,了解方法在字节 ...

  4. Java基础梳理(一)

    List和Set比较,各自的子类比较 对比一:Arraylist与LinkedList的比较 1.ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高 ...

  5. manifest.xml

    main action 和 laucher的categoty If either the MAIN action or LAUNCHER category are not declared for o ...

  6. MVC的默认约定

    MVC项目中有很多默认约定,一种是对项目目录分配的约定,比如默认情况下需要将Javascript文件放置在Script文件夹中,但这并不妨碍你将这个文件夹重新命名,也可以将整个文件夹放置到任何想要放置 ...

  7. [webrtc] RTX的处理

    以前笔记,整理 webrtc中默认开启rtx用于丢包重传,rtx的介绍可以参考rfc4588,https://tools.ietf.org/html/rfc4588#section-4 rtx使用额外 ...

  8. rack简介

    什么是rack rack是对ruby的Net::HTTP进行封装了的包,使用rack能够方便的新建一个简单的web应用. what is rack Rack describes itself as f ...

  9. Spring 小知识点

    一.引入配置文件的方式: 方式一: <context:property-placeholder location="classpath:jdbc.properties,classpat ...

  10. C/C++ -- Gui编程 -- Qt库的使用 -- 对话框QDialog

    模态对话框 -----源文件main.cpp(工程QtDialog)----- #include "qtdialog.h" #include <QApplication> ...