之前一直很好奇像sanic或者aiohttp是如何实现并发的,其实从网上看无非就是使用了asyncio,更底层就是事件驱动,libevent之类的,但是纯从应用层来讲,这个会是怎么一回事呢,举个例子:
1 2 3 4 5 6 7 8 9 10
| async def worker(): await asyncio.sleep(3) return "ok"
async def concurrent(): tasks = [worker() for _ in range(10)] await asyncio.gather(*tasks)
|
从上面代码来看,整个执行周期为3s,但是有个问题是:如果请求一个一个来,如何不阻塞呢??
1 2 3 4 5 6 7 8 9 10 11 12 13
| async def worker(message): await asyncio.sleep(3) return "result"
async def consumer(): asyncio.create_task(worker(message))
|
如果按照例如eventlet的做法:
1 2 3 4 5 6 7 8
| procpool = GreenPool(size=poolsize)
def worker(message): pass
def consumer(): gt = procpool.spawn(worker, message) gt.link(handle_message_processed, message)
|
消息过来,直接抛给pool,并不会进行阻塞,并且有poolsize控制池大小,
额,这里是sanic源码中的一部分…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
""" ------------------------------------------------- File Name: serve Description : Author : yu.zhang date: 18-7-13 ------------------------------------------------- """ import asyncio from functools import partial
class EchoServer(asyncio.Protocol): def __init__(self, loop, connections=set()): self.connections = connections self.transport = None self.loop = loop
def connection_made(self, transport): self.connections.add(self) self.transport = transport
def connection_lost(self, exc): self.connections.discard(self) print('closed:', len(self.connections))
def data_received(self, data): print(data) self.transport.write(data)
def serve(host, port, connections=None, protocol=EchoServer, loop=None, reuse_port=False): connections = connections if connections is not None else set() server = partial(protocol, loop=loop, connections=connections)
server_coroutine = loop.create_server(server, host, port, reuse_port=reuse_port) try: echo_server = loop.run_until_complete(server_coroutine) except BaseException: return try: loop.run_forever() finally: for connection in connections: print(dir(connection)) loop.run_until_complete(echo_server.wait_closed()) loop.close()
if __name__ == '__main__': loop = asyncio.get_event_loop() serve('127.0.0.1', 8080, loop=loop)
|