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多线程与队列的更多相关文章

  1. Python 多线程同步队列模型

    Python 多线程同步队列模型 我面临的问题是有个非常慢的处理逻辑(比如分词.句法),有大量的语料,想用多线程来处理. 这一个过程可以抽象成一个叫“同步队列”的模型. 具体来讲,有一个生产者(Dis ...

  2. python多线程--优先级队列(Queue)

    Python的Queue模块中提供了同步的.线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue.这些队列都实现 ...

  3. python多线程编程

    Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...

  4. Python 多线程教程:并发与并行

    转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...

  5. 【python,threading】python多线程

    使用多线程的方式 1.  函数式:使用threading模块threading.Thread(e.g target name parameters) import time,threading def ...

  6. Day9 - Python 多线程、进程

    Python之路,Day9, 进程.线程.协程篇   本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线 ...

  7. python多线程几种方法实现

    python多线程编程 Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程 ...

  8. python多线程爬虫设计及实现示例

    爬虫的基本步骤分为:获取,解析,存储.假设这里获取和存储为io密集型(访问网络和数据存储),解析为cpu密集型.那么在设计多线程爬虫时主要有两种方案:第一种方案是一个线程完成三个步骤,然后运行多个线程 ...

  9. 进程,线程,GIL,Python多线程,生产者消费者模型都是什么鬼

    1. 操作系统基本知识,进程,线程 CPU是计算机的核心,承担了所有的计算任务: 操作系统是计算机的管理者,它负责任务的调度.资源的分配和管理,统领整个计算机硬件:那么操作系统是如何进行任务调度的呢? ...

随机推荐

  1. 记个mimikatz小坑

    今晚回学校无聊搞搞自己school  实战的时候遇到mimikatz抓密码报错  以前没遇过 记一下(水一篇) 爆ERROR kuhl_m_privilege_simple ; RtlAdjustPr ...

  2. PHP in_array

    1.函数的作用:判读一个元素是否在一个数组存在 2.函数的参数: @param mixed $needle @param array $array 3. if it’s ok to use isset ...

  3. 三种常见字符编码:ASCII、Unicode和UTF-8

    什么是字符编码? 计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255( ...

  4. [JOYOI1307] 联络员

    题目限制 时间限制 内存限制 评测方式 题目来源 1000ms 131072KiB 标准比较器 Local 题目描述 Tyvj已经一岁了,网站也由最初的几个用户增加到了上万个用户,随着Tyvj网站的逐 ...

  5. JZOJ5771【NOIP2008模拟】遨游

    Description      MWH寒假外出旅游,来到了S国.S国划分为N个省,第i个省有Ti座城市,编号分别为Ci1,Ci2,……CiTi(各省城市编号不会重复).所有城市间有M条双向的道路连接 ...

  6. 1、Struts2基本入门

    一.了解了这几个主要的优点,会促使你考虑使用Struts2 : 1.POJO表单及POJO操作 - Struts2 去除掉了Struts框架中的Action Forms部分.在Struts2框架下,你 ...

  7. HDFS概述(一)

    HDFS概述(一) 1. HDFS产出的背景及定义 1.1 HDFS产生的背景 随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需 ...

  8. ssd原理及代码实现详解

    通过https://github.com/amdegroot/ssd.pytorch,结合论文https://arxiv.org/abs/1512.02325来理解ssd. ssd由三部分组成: ba ...

  9. electron调用c#动态库

    electron调用c#动态库 新建C#动态库 方法要以异步任务的方式,可以直接包装,也可以写成天然异步 代码如下 public class Class1 { public async Task< ...

  10. Qt乱码的问题

    1.在启动应用程序前加入以下代码: //配置字符编码环境,让应用程序支持中文. QTextCodec *codec = QTextCodec::codecForName("System&qu ...