Python3:同步队列Queue的使用以及源码的查看

1.声明

当前的学习来源:Python核心编程 书籍,中的多线程编程

2.导入Queue模块

from queue import Queue

3.查看当前的queue的源码

在这里插入图片描述
1.发现当前的queue模块就是一个空的类,只是提供了一些定义的方法

2.从字面意思分析这些函数的作用:

  1. empty方法返回值为bool类型(应该就是判断当前的queue中的队列长度是否为0)
  2. full 方法返回值为bool类型(应该就是判断当前的queue队列是否满(通过maxsize判断))
  3. 以get开头的方法就是获取数的方法
  4. 以put开头的方法就是存值的方法
  5. 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中是否有数据,否者会报异常!

以上纯属个人见解,如有问题请联本人!

发布了215 篇原创文章 · 获赞 39 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_45492007/article/details/103234324
今日推荐