大家好,并发编程 进入第六篇。

在第四章,讲消息通信时,我们学到了Queue消息队列的一些基本使用。昨天我在准备如何创建线程池这一章节的时候,发现对Queue消息队列的讲解有一些遗漏的知识点,而这些知识点,也并不是无关紧要的,所以在今天的章节里,我要先对Queue先做一些补充以防大家对消息队列有一些知识盲区。

再次提醒
本系列所有的代码均在Python3下编写,也建议大家尽快投入到Python3的怀抱中来。

本文目录


  • 消息队列的先进先出
  • 创建多线程的两种方式

. 消息队列的先进先出

首先,要告诉大家的事,消息队列可不是只有queue.Queue这一个类,除它之外,还有queue.LifoQueuequeue.PriorityQueue这两个类。

从名字上,对于他们之间的区别,你大概也能猜到一二吧。

queue.Queue:先进先出队列
queue.LifoQueue:后进先出队列
queue.PriorityQueue:优先级队列

先来看看,我们的老朋友,queue.Queue
所谓的先进先出(FIFO,First in First Out),就是先进入队列的消息,将优先被消费。
这和我们日常排队买菜是一样的,先排队的人肯定是先买到菜。

用代码来说明一下

import queue

q = queue.Queue()

for i in range(5):
q.put(i) while not q.empty():
print q.get()

看看输出,符合我们先进先出的预期。存入队列的顺序是01234,被消费的顺序也是01234

0
1
2
3
4

再来看看Queue.LifoQueue,后进先出,就是后进入消息队列的,将优先被消费。

这和我们羽毛球筒是一样的,最后放进羽毛球筒的球,会被第一个取出使用。

用代码来看下

import queue

q = queue.LifoQueue()

for i in range(5):
q.put(i) while not q.empty():
print q.get()

来看看输出,符合我们后进后出的预期。存入队列的顺序是01234,被消费的顺序也是43210

4
3
2
1
0

最后来看看Queue.PriorityQueue,优先级队列。
这和我们日常生活中的会员机制有些类似,办了金卡的人比银卡的服务优先,办了银卡的人比不办卡的人服务优先。

来用代码看一下

from queue import PriorityQueue

# 重新定义一个类,继承自PriorityQueue
class MyPriorityQueue(PriorityQueue):
def __init__(self):
PriorityQueue.__init__(self)
self.counter = 0 def put(self, item, priority):
PriorityQueue.put(self, (priority, self.counter, item))
self.counter += 1 def get(self, *args, **kwargs):
_, _, item = PriorityQueue.get(self, *args, **kwargs)
return item queue = MyPriorityQueue()
queue.put('item2', 2)
queue.put('item5', 5)
queue.put('item3', 3)
queue.put('item4', 4)
queue.put('item1', 1) while True:
print(queue.get())

来看看输出,符合我们的预期。我们存入入队列的顺序是25341,对应的优先级也是25341,可是被消费的顺序丝毫不受传入顺序的影响,而是根据指定的优先级来消费。

item1
item2
item3
item4
item5

. 创建多线程的两种方式

在使用多线程处理任务时也不是线程越多越好,由于在切换线程的时候,需要切换上下文环境,依然会造成cpu的大量开销。为解决这个问题,线程池的概念被提出来了。预先创建好一个较为优化的数量的线程,让过来的任务立刻能够使用,就形成了线程池。

在Python3中,创建线程池是通过concurrent.futures函数库中的ThreadPoolExecutor类来实现的。

import time
import threading
from concurrent.futures import ThreadPoolExecutor def target():
for i in range(5):
print('running thread-{}:{}'.format(threading.get_ident(), i))
time.sleep(1) #: 生成线程池最大线程为5个
pool = ThreadPoolExecutor(5) for i in range(100):
pool.submit(target) # 往线程中提交,并运行

从结果来看,前面设置线程池最大线程数5个,有生效。

running thread-11308:0
running thread-12504:0
running thread-5656:0
running thread-12640:0
running thread-7948:0 running thread-11308:1
running thread-5656:1
running thread-7948:1
running thread-12640:1
running thread-12504:1 ...
...

除了使用上述第三方模块的方法之外,我们还可以自己结合前面所学的消息队列来自定义线程池。

这里我们就使用queue来实现一个上面同样效果的例子,大家感受一下。

import time
import threading
from queue import Queue def target(q):
while True:
msg = q.get()
for i in range(5):
print('running thread-{}:{}'.format(threading.get_ident(), i))
time.sleep(1) def pool(workers,queue):
for n in range(workers):
t = threading.Thread(target=target, args=(queue,))
t.daemon = True
t.start() queue = Queue()
# 创建一个线程池:并设置线程数为5
pool(5, queue) for i in range(100):
queue.put("start") # 消息都被消费才能结束
queue.join()

输出是和上面是完全一样的效果

running thread-11308:0
running thread-12504:0
running thread-5656:0
running thread-12640:0
running thread-7948:0 running thread-11308:1
running thread-5656:1
running thread-7948:1
running thread-12640:1
running thread-12504:1 ...
...

构建线程池的方法,是可以很灵活的,大家有举可以自己多研究。但是建议只要掌握一种自己熟悉的,能快速上手的就好了。

好了,今天的内容就是这些了。


Python并发编程之消息队列补充及如何创建线程池(六)的更多相关文章

  1. Python并发编程-RabbitMQ消息队列

    RabbitMQ队列 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. MQ全称为Message Queue, 消息队列 ...

  2. python并发编程-进程间通信-Queue队列使用-生产者消费者模型-线程理论-创建及对象属性方法-线程互斥锁-守护线程-02

    目录 进程补充 进程通信前言 Queue队列的基本使用 通过Queue队列实现进程间通信(IPC机制) 生产者消费者模型 以做包子买包子为例实现当包子卖完了停止消费行为 线程 什么是线程 为什么要有线 ...

  3. JUC 并发编程--09, 阻塞队列: DelayQueue, PriorityBlockingQueue ,SynchronousQueue, 定时任务线程池: ScheduledThreadPoolExecutor

    先看DelayQueue 这个是用优先级队列实现的无界限的延迟队列,直接上代码: /** * 这个是 {@link DelayQueue} 延时队列 的验证使用类 */ class MyDelayed ...

  4. Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁

    Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...

  5. 并发编程中死锁、递归锁、进程/线程池、协程TCP服务器并发等知识点

    1.死锁 定义; 类似两个人分别被囚禁在两间房子里,A手上拿着的是B囚禁房间的钥匙,而B拿着A的钥匙,两个人都没法出去,没法给对方开锁,进而造成死锁现象.具体例子代码如下: # -*-coding:u ...

  6. Python并发编程二(多线程、协程、IO模型)

    1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...

  7. Python 3 并发编程多进程之队列(推荐使用)

    Python 3 并发编程多进程之队列(推荐使用) 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 可以往 ...

  8. python 并发编程 多进程 队列目录

    python 并发编程 多进程 队列 python 并发编程 多进程 生产者消费者模型介绍 python 并发编程 多进程 生产者消费者模型总结 python 并发编程 多进程 JoinableQue ...

  9. Python并发编程03 /僵孤进程,孤儿进程、进程互斥锁,进程队列、进程之间的通信

    Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 目录 Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 1. 僵尸进程/孤儿进 ...

随机推荐

  1. org.hibernate.hql.internal.ast.QuerySyntaxException: XXX is not mapped

    异常情况: 最近在把一个项目拆分多个 module 的时候数据库查询遇到这个异常:org.hibernate.hql.internal.ast.QuerySyntaxException: Identi ...

  2. 快排实现仿order by多字段排序

    class OrderBy(object): def __init__(self, sequence, *condition, **extra_condition): ""&quo ...

  3. Java当中的IO二

    1.大文件的读写方法 由于文件很大,我们不能一下子把文件内的所有内容都读取出来,所以只能一段一段的读取 注意:在关闭read()和write()的时候可能会产生IOException,需要对其进行处理 ...

  4. js 原型链的介绍

    对象的原型链:一个对象所拥有的属性不仅仅是它本身拥有的属性,他还会从其他对象中继承一些属性.当js在一个对象中找不到需要的属性时,它会到这个对象的父对象上去找,以此类催,这就构成了对象的原型链. 下面 ...

  5. JetBrains系列IDE快捷键大全(转载)

    编辑 快捷键组合 说明 Ctrl + Space 代码自动完成提示(选择) Alt + Enter 显示意图动作和快速修复 Ctrl + P 参数信息 (在调用方法参数忘记的时候,提示) Ctrl + ...

  6. extremecomponents

    具体教程: http://www.cnblogs.com/QQParadise/articles/1488920.html 教程中涉及到springmvc的相关知识 下载地址:http://sourc ...

  7. centOS7上编译hadoop-2.7.7

    一.阅读编译文档 在hadoop源码包根目录下有个一个BUINDING.txt的文件,文件说明了编译hadoop所需要的一些编译hadoop所需要的一些编译环境相关的东西.不同hadoop版本的要求都 ...

  8. [译文]Domain Driven Design Reference(七)—— 大型战略设计结构

    本书是Eric Evans对他自己写的<领域驱动设计-软件核心复杂性应对之道>的一本字典式的参考书,可用于快速查找<领域驱动设计>中的诸多概念及其简明解释. 上周末电脑硬盘文件 ...

  9. 实现CSS隐藏滚动条并可以滚动内容

    隐藏滚动条的同时还需要支持滚动,我们经常在前端开发中遇到这种情况,最容易想到的是加一个iscroll插件,但其实现在CSS也可以实现这个功能,我已经在很多地方使用了,下面一起看看这三种方法. 方法1: ...

  10. 对JS闭包和函数作用域的问题的深入讨论,如何理解JS闭包和函数作用域链?

    首先先引用<JavaScript权威指南>里面的一句话来开始我的博客:函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的. 因此,就出现了如下的几串代码: ...