在去年的一篇 Python 多线程编程 中学习了 Python 中如何使用多线程来调度任务,工作中也不时从自己的博客中找来参考。在运用当中不时的碰到内存消耗殆尽情况,直接把命令行窗口打死,不得不强行关窗口或杀进程。之前一直未意识到问题所在,只知任务太多就必死无疑,现在要用 Python 来处理大量任务了,必须着手来解决一下它。其实原因很简单,和 Java 的 ThreadPoolExecutor 一样(看它们用的类名都是一样的)。Java 的  ThreadPoolExecutor 内部使用了一个 Integer.MAX_VALUE 的 LinkedBlockingQueue 来存放提交的待处理的任务,所以基本上就是一个无底洞,自然解决办法也是类似的,需要一个 Bounded Queue 来存放任务列表。

在解决该问题之前自己也不妨来温习一下 Python 中使用线程池的基本模式,下面的模板代码曾经是我的最爱:

1

2

3

4

5

6

7

8

9

10

11

12

13

importtime

fromconcurrent.futuresimportThreadPoolExecutor

defperform(x):

time.sleep(2)

print(f'process {x}')

returnx+1

withThreadPoolExecutor(5)asexecutor:

foriinrange(3):

executor.submit(perform,i)

print('done')

在上面的 with 上下文中会进行以下几步

创建线程池

提交任务到线程池

等待所有任务完成

最后关闭线程池,并执行后面的代码

所以执行后的输出大概如下:

process 2

process 0

process 1

done

前三行的输出顺序不定,它们由线程池中的线程执行的,done 一定是在所有任务完成了最后输出的。

如果要收集子任务的输出,可以提交任务时放到 futures 列表中,如

1

2

3

futures.append(executor.submit(perform,i))

forfuturesinfutures:

print(future.result)

或是 executor.map() 一步提交多个任务并收集结果

1

2

3

results=executor.submit(perform,[0,1,2])

forresultinresults:

print(result)

回顾完了我们重新回到正题上来,如果不停的向线程池提交任务,待执行的任务全部要积压在线程池的工作队列中,提交多了快了,远远超出了线程池的处理速度就会迅速把本地内存挤暴。来观察一下一个 ThreadPoolExecutor 的内部属性

注意到它有一个 _work_queue 用来存放通过 submit 提交的待处理任务,默认实现为 SimpleQueue, 而 queue.SimpleQueue 是一个没有节制的队列,你可以一直往里面添加记录,只要计数没溢出并且内存充足。这就是简单使用 ThreadPoolExecutor 造成 OutOfMemory 的元凶,更可恶的是 Python 不坦诚的告诉我们内存不足,而是直接把系统拖死。

因此解决办法就是要想法设法在提交任务之前检查当前 _work_queue 大小是否超过某个限定值,是的话等降下来后再提交新任务。然而 _work_queue 是一个私有变量,不允许从外部访问,那么索性我们创造一个子类把 _work_queue 置换成一个有容量限制的 Queue, 那就是 queue.Queue. BoundedThreadPoolExecutor 并使用方式如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

importtime

fromconcurrent.futuresimportThreadPoolExecutor

fromqueueimportQueue

defperform(x):

time.sleep(2)

print(f'process {x}')

classBoundedThreadPoolExecutor(ThreadPoolExecutor):

def__init__(self,max_workers,max_waiting_tasks,*args,**kwargs):

super().__init__(max_workers=max_workers,*args,**kwargs)

self._work_queue=Queue(maxsize=max_waiting_tasks)

withBoundedThreadPoolExecutor(10,100)asexecutor:

foriinrange(999999999):

executor.submit(perform,i)

print('done')

现在操作系统再也不用担心过多的任务会把内存消耗干净了。再来看一下 BoundedThreadPoolExecutor 内部

_work_queue 变成了 queue.Queue 实现,原理是借助于 Queue 可指定 maxsize,当 Queue 的大小达到这个值,提交任务时将被阻塞,直致工作线程从中取走待执行任务,Queue 的大小低于 maxsize 值,才能继续往里头提交任务,这达到了一种流量控制的效果。

链接:

python线程池管理两个队列_Python 线程池使用有限大小的工作队列相关推荐

  1. python线程退出或应用程序请求_Python 线程和进程

    前言 学编程,谁没有为线程折腾过啊. 目录 线程与进程 线程与进程是操作系统里面的术语,简单来讲,每一个应用程序都有一个自己的进程. 操作系统会为这些进程分配一些执行资源,例如内存空间等. 在进程中, ...

  2. python如何在所有线程结束后执行最后操作_Python线程的生命周期

    在线程的生命周期中,从创建到执行以及最终终止,线程通常处于四种状态之一:开始态.可调度状态.阻塞态和终止态. 父线程和子线程 当一个新的进程或程序开始运行时,它将以一个线程开始,这个线程被称为主线程. ...

  3. python用链表求两数之和_python 算法 - 008 计算两个链表所代表的整数之和 (整数相加法)...

    python 算法 - 008 计算两个链表所代表的整数之和 (整数相加法) 知之者不如好之者, 好之者不如乐之者.--<雍也> 知道德者不如好道德者, 好道德者不如乐道德者, 是为形容人 ...

  4. Linux c 线程分离(两种方法实现线程分离)

    文章目录 1.使用函数实现线程分离 2.通过属性实现线程分离 3.杀死线程函数 1.使用函数实现线程分离 // 创建线程 int pthread_create(pthread_t &tid,c ...

  5. python线程池传入多个参数_python 线程池ThreadPoolExecutor

    背景 最近项目中需要抽取数据库中某些数据组成一个缓存表,SQL倒是不复杂就是单纯的慢,慢到navicat跑崩了也没跑出来,然后就想着用python写脚本,根据时间字段做异步查询 代码 数据库连接写成伪 ...

  6. python线程池传入多个参数_python线程池问题

    创建10个线程, 然后依次读取线程对象的值 from threading import current_thread as cthread from concurrent.futures import ...

  7. python 线程通信的几种方式_Python 线程、线程通信、多线程

    这是一篇学习Python 线程相关的内容,记录一下以备复习和开发使用,技术有限,如有问题欢迎指出,多谢. 一.GIL 全局解释器锁(cpython) 1.为什么会有这个锁:为了线程安全,减少pytho ...

  8. python 函数参数前面两个星号_Python中参数前面一个星号两个星号(*参数,**参数)起什么作用呢?...

    摘要: 下文讲述Python中参数前面一个星号两个星号的功能分享,如下所示: 在Python语言中,我们经常看见参数前面 加上一个星号或两个星号 那么这些写法到底起什么作用呢? 下文将一一道来,如下所 ...

  9. python format函数保留两位小数_python format函数

    在Python 3.0中,%操作符通过一个更强的格式化方法format()进行了增强.对str.format()的支持已经被反向移植到了Python 2.6在2.6中,8-bit字符串和Unicode ...

  10. python怎样连续输入两个数字_python实现输入数字的连续加减

    不用库,写了很久,一直出bug,到网上一搜,可以直接输入之后,eval(str)即可得到结果! eval程序如下: s=input("请输入要运算的数字") print(" ...

最新文章

  1. 在家搭建大数据分布式计算环境!
  2. 6小时完成,Jeff Dean领衔AI设计芯片方案登Nature,谷歌第四代TPU已用 芯快递 今天...
  3. 【工具】ApkTools
  4. Oracle 11g Release 1 (11.1)——简单管理聚簇
  5. c程序内存分布[转载]
  6. ACM竞赛学习整理--矩阵运算
  7. 200730学习日报6字符串
  8. Simpleperf介绍
  9. 教学一体机属于计算机的什么应用,教学一体机跟电脑有什么区别 让教学氛围有着更好的教学效果...
  10. 线性表--链式实现方式
  11. react中的render-props模式
  12. 2019年最佳作家奖
  13. JAVA中的“抽象接口”
  14. 一个移动端的在线五笔输入法
  15. 推荐一本写给IT项目经理的好书
  16. 《量子保密通信技术白皮书》
  17. 计算机网络测速创新,一种计算机网络安全测速装置的制作方法
  18. Mac如何用鼠标快速锁屏
  19. 远离危险 教你使用局域网“隐身术”(转)
  20. 一、jsp和Servlet基础理论及jstl和EL表达式用法

热门文章

  1. 工具使用——印象笔记(5)
  2. java io 字符流操作工具类
  3. 2020-09-30
  4. VMWARE 之 vSphere vCenter 安装基本配置
  5. [nRF51822] 1、一个简单的nRF51822驱动的天马4线SPI-1.77寸LCD彩屏DEMO
  6. 让驰骋工作流程引擎 ccbpm使用自定义表单来实现自己的业务逻辑.
  7. 2012-8-1复选框全选
  8. 正则表达式相关:C# RichTextBox显示html文本内容
  9. velocity include
  10. 一个hard lockup的vmcore实例解析