简单版

  

import queue
import threading class ThreadPool(object): def __init__(self, max_num=20):
self.queue = queue.Queue(max_num)
for i in range(max_num):
self.queue.put(threading.Thread) def get_thread(self):
return self.queue.get() def add_thread(self):
self.queue.put(threading.Thread) #实例化线程池对象
pool = ThreadPool(10)
#执行构造方法--实例一个max_num=10的队列,并往队列上添加10个线程类 def func(arg, p):
print(arg)
import time
time.sleep(2)
#在线程执行完前往队列里再加上一个线程类
p.add_thread() #生成30个任务
for i in range(30):
#每生成一个任务就从队列里取出一个线程类
thread = pool.get_thread()
#并实例化线程对象来执行任务
t = thread(target=func, args=(i, pool))
#线程启动后,执行func函数
t.start()

  我们可以看到,简单版的线程池就是简单的,逻辑就是每次执行一个任务就从队列取一个线程类创建一个线程,所以就有了--多少个任务,多少个线程,那和进程池相比较下,你会从中发现哪些不足呢?

  • 第一,首先问你,执行完的线程去哪呢?--被程序回收销毁了!   那么执行完这些任务有必要一对一的创建线程吗??--如果任务执行的快,一个线程有时候可以做多个任务
  • 第二,上面只规定了队列的长度,并没有规定线程池里的线程数量??
  • 第三,进程池有回调函数这么一说法,上面没有?
  • 第四,进程池里提供了close和terminate方法...

绝版

  

  好!我们来看看代码,是怎样解决上面不足的:

import queue
import threading
import contextlib
import time #放入队列里,做为线程停止运行的信号
StopEvent = object() class ThreadPool(object): def __init__(self, max_num, max_task_num = None):
#对max_task_num进行判断
if max_task_num:
#如果有值传入,在创建队列时,就按传入值限定队列长度
self.q = queue.Queue(max_task_num)
else:
#否则,就默认为队列长度为无限长
self.q = queue.Queue()
#最大线程数
self.max_num = max_num
#close方法的状态码
self.cancel = False
#terminate方法的状态码
self.terminal = False
#生成线程列表
self.generate_list = []
#空闲线程列表
self.free_list = [] def run(self, func, args, callback=None):
"""
线程池执行一个任务
:param func: 任务函数
:param args: 任务函数所需参数
:param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
:return: 如果线程池已经终止,则返回True否则None
""" #如果执行close方法,这里就会执行return--中止函数,等同不再创建线程
if self.cancel:
return
#如果空闲线程列表里为空并且已生成的线程数没有超过规定的最大线程数
if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
#那么就调用generate_thread方法创建线程
self.generate_thread()
#打包任务
w = (func, args, callback,)
#把打包的任务放入到队列里
self.q.put(w) def generate_thread(self): #创建了一个线程
t = threading.Thread(target=self.call)
#启动线程,执行call方法
t.start() def call(self):
"""
循环去获取任务函数并执行任务函数
""" #获取当前线程变量
current_thread = threading.currentThread
#把当前线程添加到生成线程列表里
self.generate_list.append(current_thread) #到队列里去拿任务
event = self.q.get()
#对取到的任务进行判断
while event != StopEvent:
#如果任务不等于停止信号,进入循环 #解任务包
func, arguments, callback = event
#尝试执行任务包里的函数
try:
#执行成功,拿到result执行结果
result = func(*arguments)
#并给执行状态赋值True
success = True
except Exception as e:
#执行失败,赋值执行状态False
success = False
#同时赋值执行结果为None
result = None if callback is not None:
#如果callback不是默认None,就尝试下列操作
try:
#把执行状态和执行结果传给回调函数,执行
callback(success, result)
except Exception as e:
pass #with上下文管理--等同把free_list,current_thread传给worker_state方法,并执行
with self.worker_state(self.free_list, current_thread):
#判断self.terminal的状态
if self.terminal:
#如果状态为True,就把任务变量设置为停止信号,等同于中止当前线程
event = StopEvent
else:
#否则,就去队列里取任务
event = self.q.get()
else:
#如果是停止信号,就把当前线程从生成线程列表中移除
self.generate_list.remove(current_thread) def close(self):
"""
执行完所有的任务后,所有线程停止
""" #当执行close方法时,就把cancel状态设置为True
self.cancel = True
full_size = len(self.generate_list)
while full_size:
#往队列里加停止信号,直到生成线程列表长度为0
self.q.put(StopEvent)
full_size -= 1 def terminate(self):
"""
无论是否还有任务,终止线程
""" #当执行terminate方法时,把terminal状态设置为True
self.terminal = True
#因为突然中止,难免队列里还有任务,所以先清空一下队列
self.q.empty()
while self.generate_list:
#往队列里加停止信号,值到生成线程列表为空时
self.q.put(StopEvent) @contextlib.contextmanager
def worker_state(self, state_list, worker_thread):
"""
用于记录线程中正在等待的线程数
""" #把执行完任务的当前线程添加到空闲线程列表里
state_list.append(worker_thread)
try:
#暂时跳出
yield
finally:
#把当前线程从空闲线程列表里移除
state_list.remove(worker_thread) # How to use pool = ThreadPool(5) def callback(status, result):
# status, execute action status
# result, execute action return value
pass def action(i):
print(i) for i in range(30):
ret = pool.run(action, (i,), callback) time.sleep(5)
print(len(pool.generate_list), len(pool.free_list))
print(len(pool.generate_list), len(pool.free_list))
# pool.close()
# pool.terminate()

           欢迎大家对我的博客内容提出质疑和提问!谢谢

                                                                             笔者:拍省先生

python基础-第九篇-9.3线程池的更多相关文章

  1. python基础-第九篇-9.2线程与多线程

    单线程 import time beginTime = time.time() for a in range(10): print(a) time.sleep(1) shijian = time.ti ...

  2. python基础-第九篇-9.1初了解Python线程、进程、协程

    了解相关概念之前,我们先来看一张图 进程: 优点:同时利用多个cpu,能够同时进行多个操作 缺点:耗费资源(重新开辟内存空间) 线程: 优点:共享内存,IO操作时候,创造并发操作 缺点:抢占资源 通过 ...

  3. Python 基础学习篇

    注:技术尚浅,时间匆忙,如有错误或者不当之处值得商榷的,请留言,吾必思而改之. 第一篇 :Python基础- 安装/变量/输入/及循环语句使用 第二篇:  Python基础- 常用数据类型 第三篇: ...

  4. python第十一天-----补:线程池

    低版本: #!/usr/bin/env python import threading import time import queue class TreadPool: ""&q ...

  5. Python并发复习4- concurrent.futures模块(线程池和进程池)

    Python标准库为我们提供了threading(多线程模块)和multiprocessing(多进程模块).从Python3.2开始,标准库为我们提供了concurrent.futures模块,它提 ...

  6. python(13)多线程:线程池,threading

    python 多进程:多进程 先上代码: pool = threadpool.ThreadPool(10) #建立线程池,控制线程数量为10 reqs = threadpool.makeRequest ...

  7. java并发编程JUC第九篇:CountDownLatch线程同步

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...

  8. 第九章 Java中线程池

    Java中的线程池是运用场景最多的并发框架,几乎所有需求异步或并发执行任务的程序都可以使用线程池.在开发过程中,合理地使用线程池能够带来3个好处. 降低资源消耗:通过重复利用已创建的线程降低线程创建和 ...

  9. Java基础知识(多线程和线程池)

    新建状态: 一个新产生的线程从新状态开始了它的生命周期.它保持这个状态直到程序 start 这个线程. 运行状态:当一个新状态的线程被 start 以后,线程就变成可运行状态,一个线程在此状态下被认为 ...

随机推荐

  1. “Chaos”的算法之Floyd算法

    倘若我们要在计算机上建立一个交通咨询系统则可以采用图的结构来表示实际的交通网络.其实现最基本的功能,求出任意两点间的最短路径, 求最短路径的经典方法有很多种,最常用的便是迪杰斯特拉算法和佛洛依德(Fl ...

  2. 【Java面试题】54 去掉一个Vector集合中重复的元素

    在Java中去掉一个 Vector 集合中重复的元素 1)通过Vector.contains()方法判断是否包含该元素,如果没有包含就添加到新的集合当中,适用于数据较小的情况下. import jav ...

  3. URAL 1203 Scientific Conference(贪心 || DP)

    Scientific Conference 之前一直在刷计算几何,邀请赛连计算几何的毛都买见着,暑假这一段时间就做多校.补多校的题目.刷一下一直薄弱的DP.多校假设有计算几何一定要干掉-.- 题意:给 ...

  4. 文件名中含有连续字符abc,相应文件中也含有字符串abc

    find ./ -name '*abc*' -exec grep 'abc' {} -H \; find ./ -name '*abc*' | xargs -I '{}' grep abc {} -H ...

  5. shell脚本中,将所有的参数值否赋给一个变量或者说将所有的参数合成一个字符串,获取所有参数

    需求描述: 在写脚本的过程中,遇到这样的一个需求,将脚本执行过程中,传递给 脚本的所有的参数,都赋值给一个变量然后在对这个变量进行处理. 测试过程: 通过以下的脚本将所有传递给脚本的变量都赋值一个变量 ...

  6. Codeforces Round #277.5 (Div. 2)部分题解

    A. SwapSort time limit per test 1 second memory limit per test 256 megabytes input standard input ou ...

  7. 工作流JBPM_day02:3-预定义的活动1_4-预定义的活动2+在图片上高亮显示正在执行的上活动

    工作流JBPM_day02:3-预定义的活动1 工作流JBPM_day02:4-预定义的活动2+在图片上高亮显示正在执行的上活动 活动 Activity 预先定义好的活动 Start开始活动 End结 ...

  8. Java精选笔记_JDBC

    JDBC 概述 什么是JDBC JDBC全称是Java数据库连接(Java Database Connectivity),应用程序可通过这套API连接到关系数据库,并使用SQL语句来完成对数据库中数据 ...

  9. POJ 3093 Margaritas(Kind of wine) on the River Walk (背包方案统计)

    题目 Description One of the more popular activities in San Antonio is to enjoy margaritas in the park ...

  10. python 协程(单线程中的异步调用)(转廖雪峰老师python教程)

    协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在 ...