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编辑  收藏  举报

导航