8-5如何使用线程池
Python2 线程池Threadpool模块已经被废弃,只在PyPI上提供下载,以支持仍然在使用的旧项目。如果是新项目,请不要再使用。使用标准库例的multiprocessing模块或者异步处理的asyncio模块。
从Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,实现了对threading和multiprocessing的进一步抽象,对编写线程池/进程池提供了直接的支持。
>>> from concurrent.futures import ThreadPoolExecutor >>>executor = ThreadPoolExecuto(3) #创建一个可以拥有3个线程的线程池 >>>def f(a,b) print(‘f’,a,b) return a ** b
1、submit()方法
>>>futer=executor.submit(f,2,3) #submit()调用线程池的一个线程去执行f()函数,第一个参数指定函数名,以后的参数是函数所需要的参数.函数运行完后,这个线程重新回到线程池中。 F 2 3 <future at 0x7f86ba1f78d0 state=running> future.result() #submit()返回函数的result()方法可以查看函数返回的值。如果调用result()函数时,submit()调用的函数还没有执行完,result()函数将阻塞,直到线程里的函数执行完。 16
2、map()方法与python内置的map方法类似。
>>>executor.map(f,[2,3,5],[4,5,6])#在多个线程上同时调用函数f()分别计算24、35、56。 f 2 4 <generator object result_iterator at 0x7f86ba1fad80> f 3 5 f 5 6
当要运行的线程数超过线程池时,那个线程会pending等待,直到线程池有空闲线程时,才会执行
>>>import time >>>def f(a,b) print(‘f’,a,b) time.sleep(10) return a ** b >>>executor.map(f,[2,3,5,6,7],[4,5,6,7,8]) <generator object result_iterator at 0x7f86ba1f9ca8> f 2 4 f 3 5 f 5 6 #此时过了一会才接着打印下面的数据, f 6 7 f 7 8
3、在上一个实验中(8.4用线程local本地数据的代码改写)
if __name__ == '__main__': streamer = JpegStreamer(0) #定义JpegStreamer线程类的对象 streamer.start() #线程启动调用 run()方法 retriever = JpegRetriever(streamer) #定义JpegRetriever类的实例, Handler.setJpegRetriever(retriever) print 'Start server...' # httpd = TCPServer(('', 9000), Handler) #TCPServer和ThreadingTCPServer的差别是。在处理每一次的http请求的时候,ThreadingTCPServer会创建一个独立的线程来执行Handler中的do_GET #httpd = ThreadingTCPServer(('', 9000), Handler) httpd = ThreadingPoolTCPServer(('', 9000), Handler,max_thread_num=3)#创建线程池数为3,并启动服务线程 httpd.serve_forever() #启动服务
跟踪ThreadingTCPServer的声明,发现这个类继承了两个类ThreadingMixIn, TCPServer
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
和多线程相关的类应该是ThreadingMixIn,继续跟踪
在ThreadingMixIn()类里有一个方法 process_request(),这个方法里面调用了threading.Thread()和t.start()说明这个函数创建的线程。
def process_request(self, request, client_address): """Start a new thread to process the request.""" t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads t.start()
那么我们继承ThreadingTCPServer这个类,再重载process_request()方法,就可以按自己的想法来实现了(使用线程池)。
from concurrent.futures import ThreadPoolExecutor Class ThreadingPoolTCPServer(ThreadingTCPServer): #def __init__():#继承要关注父类的构造器(ThreadingMixIn类无构造器,再看一下TCPServer类的构造器) def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True,max_thread_num=100):#增加一个参数,线程池的数量 super().__init__(self, server_address, RequestHandlerClass, bind_and_activate=True)#调用父类构造器,这是py3的语法,super(ThreadingPoolTCPServer,self).__init__() #这是py2的语法 self.executor = ThreadPoolExecutor(max_thread_num)#创建线程池 def process_request(self, request, client_address): """Start a new thread to process the request.""" self.executor.submit(self.process_request_thread,request, client_address)#将要创建线程的threading.Thread()的函数的参数(线程要执行的函数名,函数的参数)移到submit()函数里 “””原来创建线程并启动的部分去掉 t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads t.start() “””
posted on 2018-05-09 15:59 石中玉smulngy 阅读(214) 评论(0) 编辑 收藏 举报