python - 进击的线程池

进击的线程池

 

简单线程池的设计

一个典型的线程池,应该包括如下几个部分:
1、线程池管理器(ThreadPool),用于启动、停用,管理线程池
2、工作线程(WorkThread),线程池中的线程
3、请求接口(WorkRequest),创建请求对象,以供工作线程调度任务的执行
4、请求队列(RequestQueue),用于存放和提取请求
5、结果队列(ResultQueue),用于存储请求执行后返回的结果

 

线程池V1--简单线程池

1. 初始化队列,在队列尾部放入类

2. 取出类,执行类(线程任务)

3. 执行完成一个类后,调用初始化,创建新的类,加入队列

class LowThreadPool():

    def __init__(self, Q_nums):
        self.queue = queue.Queue(Q_nums) #创建队列
        for i in range(Q_nums): #在队列中添加Q_num个的线程任务
            self.queue.put(threading.Thread) #放置线程到队列中

    def get_low_thread(self):#获取线程任务
        return self.queue.get()

    def add_low_thread(self):#放置线程任务
        self.queue.put(threading.Thread)

def func(pool):#任务函数
    print("任务开始", pool)
    print("--------")
    time.sleep(random.randint(1,3))#随机sleep1-2秒
    print("任务结束", pool)
    time.sleep(0.5)
    pool.add_low_thread()#把完成任务的线程在加入到线程池中

p = LowThreadPool(5)#线程池中设置5个线程

for i in range(10):
    ret = p.get_low_thread()#ret = threading.Thread
    t = ret(target=func, args=(p, ))
    # t.setDaemon(True)
    t.start()

 

线程池V2 -- 加入线程管理功能

V1仅实现利用不停地创建线程去完成队列的任务,并没有循环利用已完成任务的线程重新去队列接收任务。

1. 加入两个容器,

  --generate_list = [] 真实的线程列表; --free_list = [] 空闲的线程个数

2. 线程执行管理

 将任务放在队列中 queue.put()

 着手处理任务 func, args, callback = task,

 创建线程:threading.Thread(target = func, args = (xx,))
     (限制1,是否有空闲线程,不用创建线程 if free_list=[],
      限制2, 没有空闲线程创建线程,线程个数不能超多max_num, generate_list < max
      限制3, 根据任务个数创建线程) threading.Thread()
 线程去队列中取任务 queue.get()

import threading
import queue
import time
import random


StopEvent = object()#设定线程停止对象

class HighThreadPool():

    def __init__(self, max_num):
        self.queue = queue.Queue() #创建队列
        self.max_num = max_num #线程最多创建的线程数(线程池的线程最大容量)
        self.generate_list = []#真实的线程列表,获取线程个数
        self.free_list = []#空闲的线程个数,

    def run(self, func, args, callback=None):

        tasks = (func, args, callback)#设定任务包
        self.queue.put(tasks)#把任务放入队列中

        #创建线程的条件1.线程满载,没有空闲的线程执行任务,
        #            2.线程个数不能超多max_num
        if len(self.free_list) ==0 and len(self.generate_list) < self.max_num:
            self.create_thread()#创建一个线程

    def create_thread(self): #创建线程
        t = threading.Thread(target=self.do_task)#执行task任务
        t.start()#开始线程


    # 循环获取任务并完成任务,
    # 当所有任务接近完成时,传入设定的停止StopEvent对象
    def do_task(self):
        #获取当前的线程数量
        working_thread = threading.current_thread()#current_thread() => 返回当前线程对象
        self.generate_list.append(working_thread)#把线程对象加入列表,获得线程数量

        get_task = self.queue.get()#从队列中获取 第一个 任务
        while get_task != StopEvent: #若获取元组,表示获取了任务
            #获取任务,完成线程任务,获取回调函数, 标记线程空闲,再去取任务

            func, args, callback = get_task #获取线程任务的函数,参数,返回值


            try:#建立异常,处理func函数错误操作, 回调函数根据正确或错误,作出下一步操作
                ret = func(args)#执行函数,获取返回值
                flag = True  # 异常处理设立标志默认为True

            except Exception as e:
                flag = False#出现异常,设为False
                ret = e #封装错误的信息
                pass

            # callback(flag, ret)#把函数返回值赋值给回调函数,

            if callback == None:#没有回调函数
                try:
                    callback(flag, ret)

                except Exception as e:
                    pass
            else:
                callback(flag, ret)#有返回值,执行回调函数,

            self.free_list.append(working_thread)#标记线程空闲
            get_task = self.queue.get()#执行完上一次函数, 再从队列中获取 第二个 任务
            self.free_list.remove(working_thread)#获取新的任务后,从空闲列表去除

        else:#若获取StopEvent,表示已经接近完成所有线程任务,把完成任务的线程移除

            self.generate_list.remove(working_thread)


def working(pool):#任务函数
    print("任务开始", pool)
    print("--------")
    time.sleep(random.randint(1,3))#随机sleep1-2秒
    print("任务结束", pool)
    time.sleep(0.5)
    pool.add_low_thread()#把完成任务的线程在加入到线程池中


p = HighThreadPool(10)#线程池中设置10个线程

for i in range(50):#设定50个任务
    p.run(func= working, args=(i,))

 

线程池V3 -- 完成线程的后续

V2实现循环利用线程完成列队的任务,但是在完成所有任务后,线程池中仍有正在等待任务的线程,使得程序无法终止。

1. 设定终止标记StopEvent

2. 在没有新的任务放入队列时,把StopEvent放入队列,当线程获取StopEvent后,线程自动终止。

 

import threading
import queue
import time
import random


StopEvent = object()#设定线程停止对象

class HighThreadPool():

    def __init__(self, max_num):
        self.queue = queue.Queue() #创建队列
        self.max_num = max_num #线程最多创建的线程数(线程池的线程最大容量)
        self.generate_list = []#真实的线程列表,获取线程个数
        self.free_list = []#空闲的线程个数,

    def run(self, func, args, callback=None):

        tasks = (func, args, callback)#设定任务包
        self.queue.put(tasks)#把任务放入队列中

        #创建线程的条件1.线程满载,没有空闲的线程执行任务,
        #            2.线程个数不能超多max_num
        if len(self.free_list) ==0 and len(self.generate_list) < self.max_num:
            self.create_thread()#创建一个线程


    def create_thread(self): #创建线程
        t = threading.Thread(target=self.do_task)#执行task任务
        t.start()#开始线程

    # 循环获取任务并完成任务,
    # 当所有任务接近完成时,传入设定的停止StopEvent对象
    def do_task(self):
        #获取当前的线程数量
        working_thread = threading.current_thread()#current_thread() => 返回当前线程对象
        self.generate_list.append(working_thread)#把线程对象加入列表,获得线程数量

        get_task = self.queue.get()#从队列中获取 第一个 任务
        while get_task != StopEvent: #若获取元组,表示获取了任务
            #获取任务,完成线程任务,获取回调函数, 标记线程空闲,再去取任务

            func, args, callback = get_task #获取线程任务的函数,参数,返回值


            try:#建立异常,处理func函数错误操作, 回调函数根据正确或错误,作出下一步操作
                ret = func(args)#执行函数,获取返回值
                flag = True  # 异常处理设立标志默认为True

            except Exception as e:
                flag = False#出现异常,设为False
                ret = e #封装错误的信息
                pass

            if callback == None:#没有回调函数
                try:
                    callback(flag, ret)

                except Exception as e:
                    pass
            else:
                callback(flag, ret)#有返回值,执行回调函数,


            self.free_list.append(working_thread)#标记线程空闲
            get_task = self.queue.get()#执行完上一次函数, 再从队列中获取 第二个 任务
            self.free_list.remove(working_thread)#获取新的任务后,从空闲列表去除

        else:#若获取StopEvent,表示已经接近完成所有线程任务,把完成任务的线程移除

            self.generate_list.remove(working_thread)

        #终止线程
        #1. 让正在从队列中取任务的线程挂掉
        #2. 主线程完成,在队列加上相同数量的StopEvent

    def close(self):#把StopEvent添加到队列中
        thread_num = len(self.generate_list)#从generate_list获取创建线程的个数
        while thread_num:#在队列中循环放入topEvent
            self.queue.put(StopEvent)#队列中加入StopEvent终止线程
            thread_num -= 1#线程数减少一个

 

线程池V4 -- 终止线程任务,清空队列

V3的改善后,已经明显具备模块功能,现在再加入任务被强行终止的功能。

1. 加入terminal_task = False, 默认终止任务为False, 执行终止任务为True

2. 终止线程任务后,queue.empty()清空任务队列

import threading
import queue
import time
import random


StopEvent = object()#设定线程停止对象

class HighThreadPool():

    def __init__(self, max_num):
        self.queue = queue.Queue() #创建队列
        self.max_num = max_num #线程最多创建的线程数(线程池的线程最大容量)

        self.terminal_task = False#默认终止任务为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
         """

        tasks = (func, args, callback)#设定任务包
        self.queue.put(tasks)#把任务放入队列中

        #创建线程的条件1.线程满载,没有空闲的线程执行任务,
        #            2.线程个数不能超多max_num
        if len(self.free_list) ==0 and len(self.generate_list) < self.max_num:
            self.create_thread()#创建一个线程

    def create_thread(self): #创建线程
        t = threading.Thread(target=self.do_task)#执行task任务
        t.start()#开始线程

    # 循环获取任务并完成任务,
    # 当所有任务接近完成时,传入设定的停止StopEvent对象
    def do_task(self):
        #获取当前的线程数量
        working_thread = threading.current_thread()#current_thread() => 返回当前线程对象
        self.generate_list.append(working_thread)#把线程对象加入列表,获得线程数量

        get_task = self.queue.get()#从队列中获取 第一个 任务
        while get_task != StopEvent: #若获取元组,表示获取了任务
            #获取任务,完成线程任务,获取回调函数, 标记线程空闲,再去取任务

            func, args, callback = get_task #获取线程任务的函数,参数,返回值

            try:#建立异常,处理func函数错误操作, 回调函数根据正确或错误,作出下一步操作
                ret = func(args)#执行函数,获取返回值
                flag = True  # 异常处理设立标志默认为True

            except Exception as e:
                flag = False#出现异常,设为False
                ret = e #封装错误的信息

            # callback(flag, ret)#把函数返回值赋值给回调函数,
            if callback == None:#没有回调函数
                try:
                    callback(flag, ret)
                except Exception as e:
                    pass

            else:
                callback(flag, ret)  # 有返回值,执行回调函数,

            #若只需完成部分线程,终止其他正在工作的线程,
            if self.terminal_task:#若出现终止为True
                get_task = StopEvent

            else:
                self.free_list.append(working_thread)#把正在工作的线程加入freelist
                get_task = self.queue.get() #以获得任务的线程加入StopEvent停止线程任务
                self.free_list.remove(working_thread)#移除正在工作的线程

            # self.free_list.append(working_thread)#标记线程空闲
            # get_task = self.queue.get()#执行完上一次函数, 再从队列中获取 第二个 任务
            # self.free_list.remove(working_thread)#获取新的任务后,从空闲列表去除

        # else:
        #     self.generate_list.remove(working_thread)  # 获取新的任务后,从空闲列表去除

        else:#若获取StopEvent,表示已经接近完成所有线程任务,把完成任务的线程移除

            self.generate_list.remove(working_thread)

    #完成所有任务,终止线程
    #1. 让正在从队列中取任务的线程挂掉
    #2. 主线程完成,在队列加上相同数量的StopEvent
    def close(self):#把StopEvent添加到队列中
        thread_num = len(self.generate_list)#从generate_list获取创建线程的个数
        while thread_num:#在队列中循环放入topEvent
            self.queue.put(StopEvent)#队列中加入StopEvent终止线程
            thread_num -= 1#线程数减少一个

    def terminate_task(self):#终止线程所有任务,并清空队列
        self.terminal_task = True
        #终止线程所有任务,还存在等待任务线程

        while self.generate_list:#循环读取线程列表,若终止任务后存在等待线程
            self.queue.put(StopEvent)#加入StopEvent停止线程等待

            self.queue.empty()  #清空队列任务

        # waiting_task_num = len(self.generate_list)#线程任务终止后还存在等待任务线程
        # while waiting_task_num:
        #     self.queue.put(StopEvent)#队列加入StopEvent终止
        #     waiting_task_num -= 1

def working(pool):#任务函数
    print("任务开始", pool)
    print("--------")
    time.sleep(random.randint(1,3))#随机sleep1-2秒
    print("任务结束", pool)
    time.sleep(0.5)
    pool.add_low_thread()#把完成任务的线程在加入到线程池中


p = HighThreadPool(5)#线程池中设置10个线程

for i in range(50):#设定50个任务
    p.run(func= working, args=(i,))

p.terminate_task()#终止线程任务

 

V4后,线程池的基本功能已经完成, 线程虽好,但不要贪多。

posted @ 2016-07-24 11:22  sam_r  阅读(46)  评论(0)    收藏  举报