二十三、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。

Tags: