如何使用线程池Python

#如何使用线程池
#实际案例:多线程web视频监控服务器,我们需要对请求连接数据做限制,
# 以防止恶意用户发起大量连接而导致服务器创建大量线程,最终因资源耗尽而瘫痪,
# 可以使用线程池替代原来每次请求创建的线程。
#解决方案:Python3中有线程池的实现
# 使用标准库中concurrent.futures下的ThreadPoolExecutor,
#对象的submit和map方法可以用来启动线程池中线程执行任务
"""
如何使用ThreadPoolExecutor

from concurrent.future import ThreadPoolExecutor
import time
executor =ThreadPoolExecutor(3)#创建对象
def f(a,b):#定义任务函数
  print('f',a,b)
  time.sleep(10)
  return a**b
  
future=executor.submit(f,2,4)#代用线程池线程执行函数
furture.result()
executor.map(f,[2,3,4,6,7],[4,5,6,7,8])

"""
import os,cv2,time,struct,threading
from BaseHTPSever import  HTTPSever,BaseHTTPRequestHandler
from SocketSever import TCPServer,ThreadingTCPServer
from threading import Thread,RLock
from select import select
#JpegStreamer负责采集数据  独立线程
class JpegStreamer(Thread):
    def __init__(self,camera):
        Thread.__init__(self)
        self.cap =cv2.VideoCapture(camera)
        self.lock=RLock()
        self.pipes={}
       #数据输出采用了一个注册的接口 如果想获取数据就调用这个函数
    def register(self):
        pr,pw = os.pipe()#在内部 创建管道
        self.lock.acquire()
        self.pipes[pr] =pw#维护管道的写端  来了数据从写端把数据写入进去
        self.lock.release()
        return pr#并且把管道的读端返回给用户
    def unregister(self,pr):
        self.lock.acquire()
        self.pipes.pop(pr)
        self.lock.release()
     #数据采集 返回一个生成器对象
    def capture(self):
        cap=self.cap
        while cap.isOpend():
            ret,frame=cap.read()#在其内部使用opencvde 库
            if ret:
                #ret,data=cv2.imencode('.jpg',frame)
                ret, data = cv2.imencode('.jpg', frame,(cv2.IMWRITE_JPEG_QUALITY,40))#并且编码成jpg图片
                yield data.tostring()
    #把其中的一帧发送到所有已注册的的管道当中去
    def send(self,frame):
        n=struct.pack('l',len(frame))
        self.lock.acquire()
        if len(self.pipes):
            _,pipes,_=select([],self.pipes.itervalues(),[],1)
            for pip in pipes:
                os.write(pipe,n)
        self.lock.release()

    def run(self):
        for frame in self.capture():#从capture()拿到数据
            self.send(frame)#发送给所有的管道




class JpegRetriever(object):
    def __init__(self,streamer):
        self.streamer=streamer
        #把每一个线程使用的pipe实现成线程本地数据 创建local
        self.local=threading.local()
       # self.pipe=streamer.register()

    def retrieve(self):
        while True:
            ns=os.read(self.local.pipe,8)
            n=struct.unpack('l',ns)[0]
            data=os.read(self.local.pipe,n)
            yield data
    #使用上下文管理器
    def __enter__(self):
        if hasattr(self.local,'pipe'):
            raise RuntimeError()
        self.local.pipe = streamer.register()
        return self.retrieve()
    #def cleanup(self):
    def __exit__(self, *args):
        self.streamer.unregister(self.local.pipe)
        #使用完之后删除相关属性
        del self.local.pipe
        return True#压制所有异常
class Handler(BaseHTTPRequestHandler):
    retriever =None#只有一个对象
    @staticmethod
    def setJpegRetriever(retriever):
        Handler.retriever=retriever

    def do_GET(self):
        if self.retriever is None:
            raise RuntimeError('no retriever')
        if self.path!='/':
            return
        self.send_response(200)#关于jpG响应头部的构造
        self.send_header('Cintent-type','multipart/x-mixed-replace;boundary =abcde')
        self.end_headers()
        #使用时候使用上下文管理
        with self.retriever as frames:
            #for frame in self.retriever.retrieve():
            for frame in frames:
                self.send_frame(frame)

    def send_frame(self,frame):
        self.wfile.write('--abcde\r\n')
        self.wfile.write('Content.Type:image/jpeg\r\n')
        self.wfile.write('Content.Length:image/jpeg\r\n' % len(frame))
        self.wfile.write(frame)
from  concurrent.futures import ThreadPoolExecutor

#线程池 改进class ThreadingMixIn类中的process_request方法重定义它内部的处理线程的代码
class ThreadingPoolTCPSever(ThreadingTCPServer):
      #复写方法  首先创建构造器  关注父类构造器TCPSever的参数复制过来即可
      # 然后加一个参数指定线程数量
      def  __init__(self,sever_address,RequestHandlerClass,\
                         build_and_activate=True,max_threading_num=100):
            super().__init__(sever_address,RequestHandlerClass,\
                         build_and_activate) #调用父类构造器
             #创建线程池
            self.executor=ThreadPoolExecutor(max_threading_num)
          
      def process_request(self,request,client_adress):
          self.executor().submit(self.process_request_thread,request,client_adress)
          # t=threading.Thread(target=self.process_request_thread,args=(request,client_adress))
          # t.daemon =self.daemon_threads
          # t.start()


if __name__=='__main__':
    streamer =JpegStreamer(0)
    streamer.start()

    retriever =JpegRetriever(streamer)
    Handler.setJpegRetriever(retriever)

    print('Start sever....')
    #httpd=TCPServer(('',9000),Handler)
    #httpd = ThreadingTCPServer(('', 9000), Handler)#会创建独立的线程
    #替换成线程池解决
    httpd = ThreadingPoolTCPServer(('', 9000), Handler,max_threading_num=3)#设置线程数为3
    httpd.serve_forever()

猜你喜欢

转载自blog.csdn.net/weixin_38858860/article/details/89101521