二十三、Python队列实现多线程(下篇)
@Author: Runsen
在Python中,主要采用队列和线程的方法来实现多线程。
@[TOC]
队列
队列(queue)
,是先进先出(FIFO, First-In-First-Out)
的线性表,在具体应用中通常用链表或者数组来实现,队列只允许在后端(称为rear)
进行插入操作,在前端(称为front)
进行删除操作,队列的操作方式和堆栈类似,唯一的区别在于队列只允许新数据在后端进行添加。
在Python中队列可以通过内置模块queue
导入,具体导入方法:from queue import Queue
。
queue
queue
模块提供了适合多线程编程的先进先出的数据结构,可以用来在生产者和消费者线程之间安全的传递消息或者数据;锁是调用方处理,因此多线程可以安全、方便的使用同一队列实现。
常用属性和方法:
接口 | 描述 |
---|---|
put(x) | 入队 |
get() | 出队 |
empty() | 判断队列是否为空 |
full() | 判断队列是否未满 |
qsize() | 队列的当前长度 |
task_done() | 任务结束 | join() | 等待完成 |
Queue类实现了一个基本的先进先出容器。使用put方法将元素增加到序列的一端,使用get方法从另一端删除,具体代码如下。
import queue
q = queue.Queue()
#添加元素
for i in range(5):
q.put(i)
#删除元素
while not q.empty():
print(q.get())
运行上面的程序,你将会看到下面的输出:
0
1
2
3
4
生产者/消费者模式
我们经常会遇到这样的一个问题,这里有成千上万条数据,每次需要取出其中的一条数据进行处理,那么引入多线程该怎么进行任务分配?
我们可以将数据进行分割然后交给多个线程去跑,因为线程间数据的共享的问题。
它包含两类进程:一种只是用来生产数据,例外一种只是用来消费数据.为了串联他们,通常会采用共享的数据区域,就像一个仓库.生产者产生的数据都放入仓库中并不需要关注消费者的行为,消费者只需要从共享仓库中获取数据,并不需要关心生产者的行为.
# -*- coding:utf-8 -*-
# time :2019/4/23 10:13
# Author: Maoli
import threading
import time
import random
MONEY = 0
gLock = threading.Lock()
def Procuder():
while True:
global MONEY
random_money = random.randint(10,100)
gLock.acquire() #加锁
MONEY += random_money
gLock.release() #释放锁
print ('生产者%s-生产了%d' % (threading.current_thread,random_money))
time.sleep(0.5)
def Customer():
while True:
global MONEY
random_money = random.randint(10,100)
if MONEY > random_money:
print ('消费者%s-消费了:%d' % (threading.current_thread,random_money))
gLock.acquire()
MONEY -= random_money
gLock.release()
else:
print ('需要消费的钱为:%d,余额为:%d,' % (random_money,MONEY))
time.sleep(0.5)
def p_c_test():
# 执行3个线程,来当作生产者
for x in range(3):
th = threading.Thread(target=Procuder)
th.start()
# 执行3个线程,来当作消费者
for x in range(3):
th = threading.Thread(target=Customer)
th.start()
if __name__ == "__main__":
p_c_test()
运行截图如下:
队列实现多线程
在这里我们可以使用队列与线程相结合的方式进行任务分配。在生产消费者模式当中用到的是阻塞型queue。在Python当中,我们最常用的queue就是一个支持多线程场景的阻塞队列
队列线程的思想: 首先创建一个全局共享的队列,队列中只存在有限个元素,并将所有的数据逐条加入到队列中,并调用队列的join函数进行等待。之后便可以开启若干线程,线程的任务就是不断的从队列中取数据进行处理就可以了。
# -*- coding:utf-8 -*-
# time :2019/4/23 10:35
# Author: Maoli
import threading
import time
import queue
# 下面来通过多线程来处理Queue里面的任务:
def work(q):
while True:
if q.empty():
return
else:
t = q.get()
print("当前线程sleep {} 秒".format(t))
time.sleep(t)
def main():
q = queue.Queue()
for i in range(5):
q.put(i) # 往队列里生成消息
thread_num = 5
threads = []
for i in range(thread_num):
t = threading.Thread(target=work, args=(q,))
# args需要输出的是一个元组,如果只有一个参数,后面加,表示元组,否则会报错
threads.append(t)
# 创建5个线程
for i in range(thread_num):
threads[i].start()
for i in range(thread_num):
threads[i].join()
if __name__ == "__main__":
start = time.time()
main()
print('耗时:', time.time() - start)
运行上面的程序,你将会看到下面的输出:
当前线程sleep 0 秒
当前线程sleep 1 秒
当前线程sleep 2 秒
当前线程sleep 3 秒
当前线程sleep 4 秒
耗时: 4.002955436706543
今天也学到了很多东西呢,明天有什么新知识呢?真期待鸭如果喜欢文章可以关注我哦
本文已收录 GitHub,传送门~ ,里面更有大厂面试完整考点,欢迎 Star。