loop = asyncio.get_event_loop() tasks = [] # I'm using test server localhost, but you can use any url url = "http://localhost:8080/{}" for i inrange(5): task = asyncio.ensure_future(hello(url.format(i))) tasks.append(task)
#!/usr/local/bin/python3.5 import asyncio from aiohttp import ClientSession
asyncdeffetch(url): asyncwith ClientSession() as session: asyncwith session.get(url) as response: returnawait response.read()
asyncdefrun(loop, r): url = "http://localhost:8080/{}" tasks = [] for i inrange(r): task = asyncio.ensure_future(fetch(url.format(i))) tasks.append(task) responses = await asyncio.gather(*tasks) # you now have all response bodies in this variable print(responses)
# WARNING! BROKEN CODE DO NOT COPY PASTE asyncdeffetch(url): asyncwith ClientSession() as session: asyncwith session.get(url) as response: return response.read()
pawel@pawel-VPCEH390X ~/p/l/benchmarker> ./bench.py <_GatheringFuture pending> Task was destroyed but it is pending! task: <Task pending coro=<fetch() running at ./bench.py:7> wait_for=<Future pending cb=[Task._wakeup()]> cb=[gather.<locals>._done_callback(0)() at /usr/local/lib/python3.5/asyncio/tasks.py:602]> Task was destroyed but it is pending! task: <Task pending coro=<fetch() running at ./bench.py:7> wait_for=<Future pending cb=[Task._wakeup()]> cb=[gather.<locals>._done_callback(1)() at /usr/local/lib/python3.5/asyncio/tasks.py:602]> Task was destroyed but it is pending! task: <Task pending coro=<fetch() running at ./bench.py:7> wait_for=<Future pending cb=[Task._wakeup()]> cb=[gather.<locals>._done_callback(2)() at /usr/local/lib/python3.5/asyncio/tasks.py:602]> Task was destroyed but it is pending! task: <Task pending coro=<fetch() running at ./bench.py:7> wait_for=<Future pending cb=[Task._wakeup()]> cb=[gather.<locals>._done_callback(3)() at /usr/local/lib/python3.5/asyncio/tasks.py:602]>
#!/usr/local/bin/python3.5 import asyncio from datetime import datetime from aiohttp import web import random
# set seed to ensure async and sync client get same distribution of delay values # and tests are fair random.seed(1) asyncdefhello(request): name = request.match_info.get("name", "foo") n = datetime.now().isoformat() delay = random.randint(0, 3) await asyncio.sleep(delay) headers = {"content_type": "text/html", "delay": str(delay)} # opening file is not async here, so it may block, to improve # efficiency of this you can consider using asyncio Executors # that will delegate file operation to separate thread or process # and improve performance # https://docs.python.org/3/library/asyncio-eventloop.html#executor # https://pymotw.com/3/asyncio/executors.html withopen("frank.html", "rb") as html_body: print("{}: {} delay: {}".format(n, request.path, delay)) response = web.Response(body=html_body.read(), headers=headers) return response
> time python3 bench.py 2.68user 0.24system 0:07.14elapsed 40%CPU (0avgtext+0avgdata 53704maxresident) k 0inputs+0outputs (0major+14156minor)pagefaults 0swaps
1000个请求,花费了7s。相当不错的成绩。然后10K呢?很不幸,失败了:
1 2 3 4 5 6 7 8 9
responses are <_GatheringFuture finished exception= ClientOSError(24, 'Cannot connect to host localhost:8080 ssl: False [Can not connect to localhost:8080 [Too many open files]]')> Traceback (most recent call last): File "/home/pawel/.local/lib/python3.5/site-packages/aiohttp/connector.py", line 581, in _create_connection File "/usr/local/lib/python3.5/asyncio/base_events.py", line 651, in create_connection File "/usr/local/lib/python3.5/asyncio/base_events.py", line 618, in create_connection File "/usr/local/lib/python3.5/socket.py", line 134, in __init__ OS Error: [Errno 24] Too many open files
最终因为某些原因,运行5分钟过后,它崩溃了。它生成了接近100K行的输出,所以很难定位traceback,好像某些响应没有正常关闭。具体原因不太确定。(client or server error)
一段时间的滚动以后,我找到了这个异常,在client日志中。
1 2 3 4 5 6 7
File "/usr/local/lib/python3.5/asyncio/futures.py", line 387, in __iter__ return self.result() # May raise too. File "/usr/local/lib/python3.5/asyncio/futures.py", line 274, in result raise self._exception File "/usr/local/lib/python3.5/asyncio/selector_events.py", line 411, in _sock_connect sock.connect(address) OS Error: [Errno 99] Cannot assign requested address