Python 自定义线程池,上下文管理with

python 中只为我们定了进程池,没有实现进程池,需要我们自己实现

1.简单版的线程池,通过队列来实现

import threading
import time
import queue

#简单版的线程池
class ThreadPool(object):
    def __init__(self,maxsize=10):
        self.queue = queue.Queue(maxsize)
        for i in range(maxsize):
            self.queue.put(threading.Thread) #放入的是线程类名

    #获取线程
    def get_thread(self):
        return self.queue.get()
    #放入线程
    def put_thread(self):
        self.queue.put(threading.Thread)


def func(args,pool):
    time.sleep(1)
    print(args)
    pool.put_thread() #放入线程

threadpool = ThreadPool(15) #创建一个15个的线程池
for i in range(100):
    thread = threadpool.get_thread() #获取线程
    th = thread(target=func,args=(i,threadpool,))
    th.start()

 2.高级版线程池

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import queue
import threading
import contextlib
import time

StopEvent = object()  #停止标志符


class ThreadPool(object):

    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
        #如果空闲数为0 并且产生的线程数小于最大的线程数
        if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
            self.generate_thread()  #产生线程
        w = (func, args, callback,) #封装任务元组(函数,参数,回调函数)
        self.q.put(w)  #队列中添加任务

    def generate_thread(self):
        """
        创建一个线程
        """
        t = threading.Thread(target=self.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) # 执行任务
                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:  # 默认为false ,如果terminal == True
                    event = StopEvent     #  将event设置为StopEvent,终止循环
                else:
                    event = self.q.get()   # 从队列取任务
        else: #任务等于停止标志 在产生的线程中移除当前线程
            self.generate_list.remove(current_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() #清空队列

    @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()

 3.上下文管理with

import contextlib
@contextlib.contextmanager
def test():
    print('first') # 2
    try:
        yield     # 3
    finally:
        print('third')  #5

with test():  # 1
    print('second') # 4

自定义open函数

import contextlib
@contextlib.contextmanager
def myopen(file_path,mode):
    f1 = open(file_path,mode)
    try:
        yield f1
    finally:
        f1.close()

with myopen('1.txt','r') as f:
    print(f.read())

 

posted @ 2017-05-08 14:52  1916  阅读(472)  评论(0)    收藏  举报