python线程池
版本一:简易版线程池
线程池分析:1.一个容器(最大个数) 2.取一个少一个 3.容器中没有了会阻塞等待 4.线程执行完毕交还给线程
#!/usr/bin/env python # -*- coding:utf-8 -*- import Queue import threading class ThreadPool(object): def __init__(self, max_num=20): self.queue = Queue.Queue(max_num) for i in xrange(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) def func(arg, p): print arg import time time.sleep(2) p.add_thread() for i in xrange(30): thread = pool.get_thread() t = thread(target=func, args=(i, pool)) t.start()
缺点:线程没有被重用,被垃圾回收回收
版本二:复杂点
#!/usr/bin/env python # -*- coding:utf-8 -*- import queue import threading import contextlib import time StopEvent = object() # object() 是所有实例的方法,空方法 class ThreadPool(): def __init__(self, max_num, max_task_num = None): if max_task_num: self.q = queue.Queue(max_task_num) # 创建队列对象,用来装任务,有值的话就设置最大值 else: self.q = queue.Queue() # 没有值的话,这个队列就无限大 self.max_num = max_num # 最大线程数 self.cancel = False # 终止线程用的 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 """ if self.cancel: return if len(self.free_list) == 0 and len(self.generate_list) < self.max_num: # 判断已经创建的线程是否小于最大线程数,空闲线程个数是不是等于0 self.generate_thread() # 空闲线程数=0,小于最大线程数,就创建新线程 w = (func, args, callback,) # 上述不满足就把任务放进队列,把3个参数当做一个元组传进队列 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 = func(*arguments) # 执行action函数 success = True except Exception as e: success = False result = None if callback is not None: try: callback(success, result) except Exception as e: pass # 将当前线程设置为空闲 # 等待着.... # 有任务来了... # 当前线程的状态,不在空闲 with self.worker_state(self.free_list, current_thread): # if self.terminal: event = StopEvent else: event = self.q.get() else: self.generate_list.remove(current_thread) # 如果队列中的任务等于空函数StopEvent就把当前的线程移除掉 @contextlib.contextmanager # 有了此装饰器就能使用with self.worker_state()执行上下文切换 def worker_state(self, state_list, worker_thread): """ 用于记录线程中正在等待的线程数 """ state_list.append(worker_thread) try: yield # 执行到这时,会跳出此函数,去执行with self.worker_state()函数,执行完毕时,再跳回此函数继续执行下面的代码 finally: state_list.remove(worker_thread) def close(self): """ 执行完所有的任务后,所有线程停止 """ self.cancel = True full_size = len(self.generate_list) # 以创建线程有多少就创建多少个空函数 while full_size: # 然后把空函数放进队列中,让每一个线程取到任务 self.q.put(StopEvent) full_size -= 1 def terminate(self): """ 无论是否还有任务,终止线程 """ self.terminal = True while self.generate_list: self.q.put(StopEvent) self.q.queue.clear() # 把队列都清空 # 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): # 创建30个任务 ret = pool.run(action, (i,), callback) # 3个参数,函数名,元组,函数名 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()
更多参见:twisted.python.threadpool
上下文管理:https://docs.python.org/2/library/contextlib.html
上下文实例1
#!/usr/bin/env python # -*- coding:utf-8 -*- import contextlib @contextlib.contextmanager def worker_state(state_list, worker_thread): """ 用于记录线程中正在等待的线程数 """ state_list.append(worker_thread) try: yield finally: state_list.remove(worker_thread) free_list = [] current_thread = 'python' with worker_state(free_list, current_thread): # 如果上述执行完了,则这个线程就闲了 print('redhat') print('centos')
上下文实例2
#!/usr/bin/env python # -*- coding:utf-8 -*- import contextlib import socket @contextlib.contextmanager def context_socket(host,port): sk = socket.socket() sk.bind((host,port)) sk.listen(5) try: yield sk finally: sk.close() with context_socket('127.0.0.1',8888) as sock: # 如果上述执行完了,则这个线程就闲了 print(sock)