根据cookbook, 多线程情况的事件驱动IO

来源:互联网 发布:淘宝反光衣 编辑:程序博客网 时间:2024/05/29 08:39

模拟使用线程池, 事件驱动IO模型, 这里使用的select

1. 采用对socket,初始化完成之后,内核状态是不可读,不可写(无东西可读)

2. 线程池完成工作之后, 回调_complete, 把线程计算结果及回调函数放入pending的list

3. 发送一个字节, 告诉内核select, 返回flieno那个socket可读,执行handle_receive把pending依次处理完成。

应用场景:

接收大量的fd,内存多大接多少

线程池处理结果

回调, fd清理收尾


#!/usr/bin/env pythonclass EventHandler(object):    """An I/O event loop    """    def fileno(self):        raise NotImplemented    def wants_to_receive(self):        """Return True if receiving is allowed        """        return False    def handle_receive(self):        """Perform the receive operation        """        pass    def wants_to_send(self):        """Return True if sending is requested        """        return False    def handle_send(self):        """send data        """        passfrom concurrent.futures import ThreadPoolExecutorimport socketclass ThreadPoolHandler(EventHandler):def __init__(self, nworkers=3):a = socket.socket(socket.AF_INET, socket.SOCK_STREAM)a.bind(('127.0.0.1', 0))a.listen(1)connect_address = a.getsockname()self.writer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.writer.connect(connect_address)self.reader, addr = a.accept()a.close()self.pending = []self.pool = ThreadPoolExecutor(nworkers)def fileno(self):return self.reader.fileno()def _complete(self, callback, r):self.pending.append((callback, r.result()))self.writer.send(b'x')  # wakedef run(self, func, args={}, kwargs={}, *, callback):r = self.pool.submit(func, *args, **kwargs)r.add_done_callback(lambda r: self._complete(callback, r))def wants_to_receive(self):return Truedef handle_receive(self):"""Run callback functions of complete work"""for callback, result in self.pending:callback(result)self.reader.recv(1)  # recv xself.pending = []class UDPServer(EventHandler):    """An UDP io event loop handler    """    def __init__(self, address):        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)        self.sock.bind(address)        def fileno(self):        return self.sock.fileno()    def wants_to_receive(self):        # blocking        return True     import select def event_loop(handlers):    while True:        wants_recv = [h for h in handlers if h.wants_to_receive()]        wants_send = [h for h in handlers if h.wants_to_send()]        can_recv, can_send, err = select.select(wants_recv, wants_send, [])        for h in can_recv:            h.handle_receive()        for h in can_send:            h.handle_send()def fib(n):if n < 2:return 1else:return fib(n-1) + fib(n-2)class UDPFibServer(UDPServer):def handle_receive(self):msg, addr = self.sock.recvfrom(1024)n = int(msg)pool.run(fib, (n,), callback=lambda r: self.respond(r, addr))def respond(self, result, addr):self.sock.sendto(str(result).encode("ascii"), addr)if __name__ == "__main__":pool = ThreadPoolHandler(16)handlers = [pool, UDPFibServer(('', 7777))]event_loop(handlers)


0 0
原创粉丝点击