队列的概念
新一配 抛开计算机知识体系,在咱们的生活中,队列这个词其实挺好想象的,因为无时无刻都可以见到。比如等公交的时候,需要排队。比如买东西交钱的时候,也要排队。在这些例子中,由人们有序形成的队形就叫队列。
新一配,生活中的排队,有没有什么特性而言呢?大家可以思考下,再往下看。
普通队列的特性,即先进先出(FIFO,first in first out)。对应到生活中,怎么理解这个先进先出?其实很好理解。
拿排队买东西来说,每次排在队首的人,交完钱肯定是当前队列中第一个离开收银台的人。当队首的人离开了,那么后面的所有人都要往前走,继续结账。
对应到计算机中的队列,就是因为第一个人先排的队,所以他第一个交完钱就可以离开了,即先进先出。(多说句,计算机世界许多东西其实就是抽象的现实世界示例。)
心细的同学会发现,在上面将普通两字标粗了,那一定还有一些其它的常用特殊队列,比如优先级队列。(PriorityQueue)
这次拿去银行办业务来举例。生活中我们去银行办理业务,一般都需要去机器拿号,然后等待着柜台业务人员叫号。叫到你,你就过去处理就行了。但是银行是有 vip 服务的,拥有 vip 权益的人可以更快的享受到业务办理,也就是说人家比你有更高的优先权。vip特权通道,你值得拥有!
了解了生活中的例子,再来看看比较专业的定义:
优先级队列(priority queue) 是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有(1)查找(2)插入一个新元素 (3)删除 一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素 。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。
百度百科
也就是说,在优先级队列中,每个人都有一个优先权对应,谁的优先权高,谁就会先被处理。大家了解即可。
示例演示
示例情景:
假设下面有 6 个美少女,她们准备去量身高,恰好这几个妹纸是按照从高到低,从大到小排好队的。
每走一个去量身高,这个队列中就会少一个人。当然,队首在左,队尾在右,于是她们的变化是下面这样:
代码演示
是不是好多人看到这里就不打算看了。。不是让你来看美少女的喂。。。下面才是重点~
第一部分代码:
import queue
import threading
num_worker_threads = 5
def do_work(beauty_dict):
print(f"妹纸名字{beauty_dict['name']},年龄{beauty_dict['age']}")
def worker():
while True:
item = q.get()
if item is None:
break
do_work(item)
q.task_done()
简单的讲解下,在 Python3 中,有个模块叫 queue。里面实现了几个队列的数据结构。首先看 do_work() 函数,其中它就是用来打印妹子姓名和年龄的。worker() 函数中写了一层死循环,只要队列中有妹纸的数据,就一直执行打印,直到队列中的妹纸都没了,就跳出。
第二部分代码:
q = queue.Queue()
threads = []
for i in range(num_worker_threads):
t = threading.Thread(target=worker)
t.start()
threads.append(t)
beauty_girls = [{"name": "小H", "age": 23},
{"name": "小E", "age": 22},
{"name": "小D", "age": 21},
{"name": "小C", "age": 20},
{"name": "小B", "age": 19},
{"name": "小A", "age": 18},
]
for item in beauty_girls:
q.put(item)
# block until all tasks are done
q.join()
# stop workers
for i in range(num_worker_threads):
q.put(None)
for t in threads:
t.join()
首先创建队列,其次,让这 6 个美少女开始依次排入到队列中,开启多线程去执行 worker() 这个函数。worker() 函数就是第一部分代码中,从队列里一个个取出妹纸,在调用 do_work() 打印她们的姓名和年龄。
关于队列的 join() 方法,可以看到官方给的英文注释,大意是当所有任务完成时才继续执行后面的代码,否则处于阻塞状态。
总结
通过两篇文章,简单的介绍了一下多线程和队列,目的是为了接下来的多线程队列爬虫示例做准备,如果对这些不了解的话,在后面的代码中是很难看懂的。
关于队列的使用,最常用的方法应该就是放入、获取、判断队列的大小。其实这三点在大部分数据结构里都是常用的操作,熟练掌握即可。
新一配本章完整代码,就是文中第一部分和第二部分的代码拼接,因为太长,所以分开讲了下。
新一配,如果大家有什么问题想沟通,可以留言交流哈!