1.声明
当前的学习来源:Python核心编程
书籍,中的多线程编程
2.导入Queue模块
from queue import Queue
3.查看当前的queue的源码
1.发现当前的queue模块就是一个空的类,只是提供了一些定义的方法
2.从字面意思分析这些函数的作用:
empty方法返回值为bool类型(应该就是判断当前的queue中的队列长度是否为0)
full 方法返回值为bool类型(应该就是判断当前的queue队列是否满(通过maxsize判断))
以get开头的方法就是获取数的方法
以put开头的方法就是存值的方法
qsize方法就是获取这个队列的实际长度的方法
以上查看了这个queue类的所有方法,但是没有发现当前的队列移除的方法(remove方法没有)
4.查看当前的Queue的源码
1.首先查看这个类的构造方法
def __init__(self, maxsize=0):
#如果没有设置maxsize属性就表示当前默认创建一个大小为0的queue队列
self.maxsize = maxsize
self._init(maxsize)
# 获取多线程锁,通过threading.Lock()方法是获得锁,类似于前面的threading的使用
self.mutex = threading.Lock()
通过threading.Condition创建一个条件,相当于ReentLock方法中的Condition使用方式可能完全一样
self.not_empty = threading.Condition(self.mutex)
self.not_full = threading.Condition(self.mutex)
self.all_tasks_done = threading.Condition(self.mutex)
self.unfinished_tasks = 0
这个构造函数就是用来创建当前所需要的线程的锁,并创建对应的条件锁
2.查看其中的put方法
def put(self, item, block=True, timeout=None):
# 通过当前的not_full锁对象判定当前是否可以添加数据
with self.not_full:
if self.maxsize > 0: # 如果当前的数量为零:表示当前的queue中并没有数据
if not block: # 判断当前是否存在阻塞对象
if self._qsize() >= self.maxsize:#如果当前的队列是否已经满了
raise Full # 扔出一个队列已满的异常
elif timeout is None: # 判断是否存在超时时间,如果不存在
while self._qsize() >= self.maxsize:# 判断当前的queue中的数据是否已经满了
self.not_full.wait()# 满了就不允许添加任何数据,让添加数据的线程阻塞
elif timeout < 0:#如果当前传入的超时参数小于零,就抛出异常
raise ValueError("'timeout' must be a non-negative number")
else:# 否者通过超时时间判断当前的数据是否超时
endtime = time() + timeout # 获取超时时间
while self._qsize() >= self.maxsize:
remaining = endtime - time()
if remaining <= 0.0:
raise Full #当前获取数据的时间已经超时就扔出异常
self.not_full.wait(remaining)# 否者就让当前put的线程等待
self._put(item) # 最后向当前的数据中添加数据
self.unfinished_tasks += 1
self.not_empty.notify() # 唤醒get的线程开始执行任务
当前的添加数据操作中具有让线程阻塞的代码,以及唤醒线程的操作
3.查看self_put方法
# Put a new item in the queue
def _put(self, item):
self.queue.append(item)
就是一个简单的向queue的后面追加数据的操作
4.查看当前的get方法
def get(self, block=True, timeout=None):
with self.not_empty:# 如果当前的线程是不空线程就是可以执行拿出操作的线程
if not block:# 如果当前的状况是不阻塞的
if not self._qsize():# 判断当前的集合的长度如果为0就抛出空异常
raise Empty
elif timeout is None:# 判断超时时间是否为空
while not self._qsize():#如果长度为0,就让当前的get线程等待
self.not_empty.wait()
elif timeout < 0:# 如果当前的超时时间为小于0,就扔出异常
raise ValueError("'timeout' must be a non-negative number")
else:
endtime = time() + timeout
while not self._qsize():
remaining = endtime - time()
if remaining <= 0.0:
raise Empty
self.not_empty.wait(remaining)
item = self._get()#最后执行获取操作通过调用本身的_get方法执行
self.not_full.notify()# 唤醒put添加线程
return item
5.查看self._get方法
# Get an item from the queue
def _get(self):
return self.queue.popleft()
发现当前的_get方法调用的实际上是当前的popleft方法
,pop方法常用于当前的出栈操作,所以这个的get方法实际上会移除当前的queue中的第一个数据并返回
到这里,就基本上解析完成了,当前的queue操作只有通过get方法删除指定下标中的数据,和获取数据,使用put方式添加数据,当中涉及到使用threading.Lock方式创建的锁以及各种Condition锁
,所以当前的Queue就是一个线程安全的集合
5.简单的使用Queue(非多线程环境的使用)
# 用于三实现当前的Queue的生产者和消费者的测试
# 首先测试当前的Queue的基本功能,首先第一步需要从当前的queue模块中导入需要的Queue
from queue import Queue
# 这里是迭代queue的操作,需要通过get下标的方式获取当前对应下标的数据
def print_collection(my_queue=Queue):
print("当前queue队列的大小为:%d" % (my_queue.qsize())) # 通过当前的Queue.qsize方法获取当前队列的实际的大小
print("开始迭代当前的queue中的元素================")
for i in range(my_queue.qsize()): # 这里开始循环的迭代操作
print("取出数据为:%s,其大小为:%d" % (my_queue.get(i), my_queue.qsize()))
# queue通过get(下标)方式获取数据,通过put方法添加数据
# 向当前的同步队列中添加数据
def put_into_queue(my_queue=Queue):
my_queue.put("admin1")
my_queue.put("admin2")
my_queue.put("admin3")
# 向当前的同步队列中移除数据,通过查询当前的queue模块发现其中没有一个具有remove的方法
# 通过源码发现其中的get方法实际上就是:self._queue.popleft() ,看到这个popleft就是从左边拿出一个数据并返回,所以get方法实际上就是移除
def remove_into_queue(my_queue=Queue):
# my_queue.__delattr__("admin1")
pass
# 测试当前的清空方法
def empty_into_queue(my_queue=Queue):
my_queue.empty()
def main():
print("这里是main函数的入口!")
my_queue = Queue()
put_into_queue(my_queue)
# remove_into_queue(my_queue)
print_collection(my_queue)
print_collection(my_queue)
if __name__ == "__main__":
main()
执行的结果为:
6.多线程的环境下的Queue的使用
# 在多线程的情况下使用当前的同步队列
from queue import Queue
import threading
import time
class Sum:
my_queue = Queue()
count = 0
def sum():
while Sum.count < 9:
time.sleep(1)
if not Sum.my_queue.empty():
Sum.count = Sum.my_queue.get(0)
print("当前获取的数据为:%d" % (Sum.count))
Sum.count += 1
Sum.my_queue.put(Sum.count)
print("执行++操作后的数据结果为:%d" % (Sum.count))
def main():
Sum.my_queue.put(0)
threading.Thread(target=sum, name="线程一").start()
threading.Thread(target=sum, name="线程二").start()
threading.Thread(target=sum, name="线程三").start()
if __name__ == '__main__':
print("主线程的开启。。。。。")
main()
print("主线程的结束。。。。。")
执行的结果为:
这里没有发现线程的安全,但是需要注意当前如果获取不到数据就会一直报空异常
7.总结
1.在使用当前的Queue队列的时候需要先导入模块:from queue import Queue
2.当前的Queue模块是一个同步队列模块,通过put放入值,通过get方法取出和移除数据(这里需要注意)
3.在执行get的操作的时候需要注意当前Queue中是否有数据,否者会报异常!
以上纯属个人见解,如有问题请联本人!