Python多线程与队列
Python多线程与Queue队列多线程在感官上类似于同时执行多个程序,虽然由于GIL的存在,在Python中无法实现线程的真正并行,但是对于某些场景,多线程仍不失为一个有效的处理方法:
1,不紧急的,无需阻塞主线程的任务,此时可以利用多线程在后台慢慢处理;
2,IO密集型操作,比如文件读写、用户输入和网络请求等,此时多线程可以近似达到甚至优于多进程的表现;
多线程的基本使用不再赘述,以下语法便可轻松实现:
def task(args1, args2):
pass Thread(
target=task,
args=(args1, args2)
).start()
这里我们重点关注线程通信。
假设有这么一种场景:有一批源数据,指定一个操作系数N,需要分别对其进行与N的加减乘除操作,并将结果汇总。
当然这里的加减乘除只是一种简单处理,在实际的生产环境中,它其实代表了一步较为复杂的业务操作,并包含了较多的IO处理。
自然我们想到可以开启多线程处理,那么紧接着的问题便是:如何划分线程,是根据处理步骤划分,还是根据源数据划分?
对于前者,我们把涉及的业务操作单独划分位一个线程,即有4个线程分别进行加减乘除的操作,显然上一个线程的结果是下一个线程的输入,这类似于流水线操作;
而后者则是把源数据分为若干份,每份启动一个线程进行处理,最终把结果汇总。一般来说,我们推荐第一种方式。因为在一个线程中完成所有的操作不如每步一个线程清晰明了,
尤其是在一些复杂的场景下,会加大单个线程的出错概率和测试难度。
那么我们将开辟4个线程,分别执行加减乘除操作。最后一个除法线程结束则任务完成:
#!/usr/bin/env python
# -*- coding: utf-8 -*- from Queue import Queue
from threading import Thread class NumberHandler(object):
def __init__(self, n):
self.n = n def add(self, num):
return num + self.n def subtract(self, num):
return num - self.n def multiply(self, num):
return num * self.n * self.n def divide(self, num):
return num / self.n class ClosableQueue(Queue):
SENTINEL = object() def close(self):
self.put(self.SENTINEL) def __iter__(self):
while True:
item = self.get()
try:
if item is self.SENTINEL:
return
yield item
finally:
self.task_done() class StoppableWorker(Thread):
def __init__(self, func, in_queue, out_queue):
super(StoppableWorker, self).__init__()
self.in_queue = in_queue
self.out_queue = out_queue
self.func = func def run(self):
for item in self.in_queue:
result = self.func(item)
self.out_queue.put(result)
print self.func if __name__ == '__main__':
source_queue = ClosableQueue()
add_queue = ClosableQueue()
subtract_queue = ClosableQueue()
multiply_queue = ClosableQueue()
divide_queue = ClosableQueue()
result_queue = ClosableQueue() number_handler = NumberHandler(5) threads = [
StoppableWorker(number_handler.add, add_queue, subtract_queue),
StoppableWorker(number_handler.subtract, subtract_queue, multiply_queue),
StoppableWorker(number_handler.multiply, multiply_queue, divide_queue),
StoppableWorker(number_handler.divide, divide_queue, result_queue),
] for _thread in threads:
_thread.start() for i in range(10):
add_queue.put(i) add_queue.close()
add_queue.join()
print 'add job done...'
subtract_queue.close()
subtract_queue.join()
print 'subtract job done...'
multiply_queue.close()
multiply_queue.join()
print 'multiply job done...'
divide_queue.close()
divide_queue.join()
print 'divide job done...'
result_queue.close() print "%s items finished, result: %s" % (result_queue.qsize(), result_queue) for i in result_queue:
print i
运行结果:
线程执行日志:

总的结果:

可见线程交叉运行,但是任务却是顺序结束,这符合我们的预期。
值得注意的是,我们在ClosableQueue定义了一个close()方法,通过放入一个特殊的类变量SENTINEL告诉队列应该关闭。此外,由于直接加减乘除结果不变,因此我特意乘了两次来便于我们判断结果。
总结:
1. Queue是一种高效的任务处理方式,它可以把任务处理流程划分为若干阶段,并使用多条python线程来同时执行这些子任务;
2. Queue类具备阻塞式的队列操作、能够指定缓冲区尺寸,而且还支 持join方法,这使得开发者可以构建出健壮的流水线。
Python多线程与队列的更多相关文章
- Python 多线程同步队列模型
Python 多线程同步队列模型 我面临的问题是有个非常慢的处理逻辑(比如分词.句法),有大量的语料,想用多线程来处理. 这一个过程可以抽象成一个叫“同步队列”的模型. 具体来讲,有一个生产者(Dis ...
- python多线程--优先级队列(Queue)
Python的Queue模块中提供了同步的.线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue.这些队列都实现 ...
- python多线程编程
Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...
- Python 多线程教程:并发与并行
转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...
- 【python,threading】python多线程
使用多线程的方式 1. 函数式:使用threading模块threading.Thread(e.g target name parameters) import time,threading def ...
- Day9 - Python 多线程、进程
Python之路,Day9, 进程.线程.协程篇 本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线 ...
- python多线程几种方法实现
python多线程编程 Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程 ...
- python多线程爬虫设计及实现示例
爬虫的基本步骤分为:获取,解析,存储.假设这里获取和存储为io密集型(访问网络和数据存储),解析为cpu密集型.那么在设计多线程爬虫时主要有两种方案:第一种方案是一个线程完成三个步骤,然后运行多个线程 ...
- 进程,线程,GIL,Python多线程,生产者消费者模型都是什么鬼
1. 操作系统基本知识,进程,线程 CPU是计算机的核心,承担了所有的计算任务: 操作系统是计算机的管理者,它负责任务的调度.资源的分配和管理,统领整个计算机硬件:那么操作系统是如何进行任务调度的呢? ...
随机推荐
- 浏览器渗透框架BeEF使用笔记(二)
0x03 常用模块 1-信息收集 可以收集到例如 浏览器名称版本 浏览器用户版本 插件(包括Java,ActiveX,VBS,Flash……) 窗口大小 1)details面板收集 (2)插件收集信息 ...
- Math中ceil中为什么会有负零
double c=Math.ceil(-0.5); double d=Math.floor(0.5); System.out.println(c); System.out.println(d); Sy ...
- MySQL 日志系统之 redo log 和 binlog
之前我们了解了一条查询语句的执行流程,并介绍了执行过程中涉及的处理模块.一条查询语句的执行过程一般是经过连接器.分析器.优化器.执行器等功能模块,最后到达存储引擎. 那么,一条 SQL 更新语句的执行 ...
- openssl之aes对称加密
AES:密码学中的高级加密标准(Advanced Encryption Standard,AES),又称 Rijndael加密法. 对称加密:用同一个密码 加密/解密 文件. 使用openssl中 ...
- 可实现的全局唯一有序ID生成策略
在博客园搜素全局唯一有序ID,罗列出来的文章大致讲述了以下几个问题,常见的生成全局唯一id的常见方法 :使用数据库自动增长序列实现 : 使用UUID实现: 使用redis实现: 使用Twitter的 ...
- 实践开发:vue框架重点知识分析
一个VUE项目的主树: assets文件夹是放静态资源: components是放组件: router是定义路由相关的配置; view视图: app.vue是一个应用主组件: main.js是入口文件 ...
- VSCode 配置 Python 开发环境
一.环境准备 首先需要先安装好 Python 和 VSCode, 下载地址如下 VSCode Python 二.安装 Python 扩展 首先在VSCode上安装 Python 扩展,如图: 三.新建 ...
- java架构之路-(Redis专题)简单聊聊redis分布式锁
这次我们来简单说说分布式锁,我记得过去我也过一篇JMM的内存一致性算法,就是说拿到锁的可以继续操作,没拿到的自旋等待. 思路与场景 我们在Zookeeper中提到过分布式锁,这里我们先用redis实现 ...
- Js极客之路 - 简化操作
1.对字符串使用单引号(避免动态添加元素时html会出现的双引号"引起的冲突,方便操作 - 单引号一个键,双引号两个键) // bad var name = "Barrior&qu ...
- 现在Java 桌面应用程序能做到什么程度(Spring Boot+JavaFX2开发)
Spring Boot - JavaFX 2.0应用 很多人对Java开发native程序第一反应还停留在暗灰色单一风格的Java GUI界面,开发方式还停留在AWT或者Swing.本文主要基于Spr ...