AIOHTTP
https://docs.aiohttp.org/en/stable/
异步HTTP客户端和服务器,为asyncio 设计。
因为 作为客户端的 requests 支持同步请求模式, 一个请求完成后,才能执行下一个请求。
Asynchronous HTTP Client/Server for asyncio and Python.
Key Features¶
Supports both Client and HTTP Server.
Supports both Server WebSockets and Client WebSockets out-of-the-box without the Callback Hell.
Web-server has Middlewares, Signals and plugable routing.
CLIENT CODE
https://docs.aiohttp.org/en/stable/
import aiohttp import asyncio async def main(): async with aiohttp.ClientSession() as session: async with session.get('http://python.org') as response: print("Status:", response.status) print("Content-type:", response.headers['content-type']) html = await response.text() print("Body:", html[:15], "...") loop = asyncio.get_event_loop() loop.run_until_complete(main())
SERVER CODE
from aiohttp import web async def handle(request): name = request.match_info.get('name', "Anonymous") text = "Hello, " + name return web.Response(text=text) app = web.Application() app.add_routes([web.get('/', handle), web.get('/{name}', handle)]) if __name__ == '__main__': web.run_app(app)
WEBSOCKET SERVER CODE
https://github.com/aio-libs/aiohttp
# examples/server_simple.py from aiohttp import web async def handle(request): name = request.match_info.get('name', "Anonymous") text = "Hello, " + name return web.Response(text=text) async def wshandle(request): ws = web.WebSocketResponse() await ws.prepare(request) async for msg in ws: if msg.type == web.WSMsgType.text: await ws.send_str("Hello, {}".format(msg.data)) elif msg.type == web.WSMsgType.binary: await ws.send_bytes(msg.data) elif msg.type == web.WSMsgType.close: break return ws app = web.Application() app.add_routes([web.get('/', handle), web.get('/echo', wshandle), web.get('/{name}', handle)]) if __name__ == '__main__': web.run_app(app)
WHY TO USE IT?
https://www.twilio.com/blog/asynchronous-http-requests-in-python-with-aiohttp
鉴于 asyncio 成为标准的第三方库, 很多第三方的包提供了兼容功能, 异步范式渐渐流形。
aiohttp就是来做异步http请求的。
但是为什么要异步呢, 这就要从 非阻塞 说起。
Asynchronous code has increasingly become a mainstay of Python development. With asyncio becoming part of the standard library and many third party packages providing features compatible with it, this paradigm is not going away anytime soon.
Let's walk through how to use the aiohttp library to take advantage of this for making asynchronous HTTP requests, which is one of the most common use cases for non-blocking code.
WHY TO BE ASYNCHRONOUS?
异步代码,就是非阻塞代码。
当一个routine遇到IO访问结果暂时不能获得的情况, 那么此routine可以暂停, 释放计算资源给其它的routine使用。
而阻塞的代码, 则会死等结果返回, 尽管此过程计算资源空闲, 也不释放。
What is non-blocking code?
You may hear terms like "asynchronous", "non-blocking" or "concurrent" and be a little confused as to what they all mean. According to this much more detailed tutorial, two of the primary properties are:
- Asynchronous routines are able to “pause” while waiting on their ultimate result to let other routines run in the meantime.
- Asynchronous code, through the mechanism above, facilitates concurrent execution. To put it differently, asynchronous code gives the look and feel of concurrency.
So asynchronous code is code that can hang while waiting for a result, in order to let other code run in the meantime. It doesn't "block" other code from running so we can call it "non-blocking" code.
The asyncio library provides a variety of tools for Python developers to do this, and aiohttp provides an even more specific functionality for HTTP requests. HTTP requests are a classic example of something that is well-suited to asynchronicity because they involve waiting for a response from a server, during which time it would be convenient and efficient to have other code running.
Making a large number of requests
https://www.twilio.com/blog/asynchronous-http-requests-in-python-with-aiohttp
作为客户端,可以同时发起很多条请求,但是不用占用较多资源, 跟进程和线程相比。
多个routine同属于一个进程的线程, 不会导致线程和进程的切换。
import aiohttp import asyncio import time start_time = time.time() async def main(): async with aiohttp.ClientSession() as session: for number in range(1, 151): pokemon_url = f'https://pokeapi.co/api/v2/pokemon/{number}' async with session.get(pokemon_url) as resp: pokemon = await resp.json() print(pokemon['name']) asyncio.run(main()) print("--- %s seconds ---" % (time.time() - start_time))
Utilizing asyncio for improved performance
https://www.twilio.com/blog/asynchronous-http-requests-in-python-with-aiohttp
上面使用循环方式, 发起异步请求。
但是如果提前准备好 异步对象, 然后使用 asyncio去统一出发异步对象执行, 并返回结果, 则效率要高得多。
import aiohttp import asyncio import time start_time = time.time() async def get_pokemon(session, url): async with session.get(url) as resp: pokemon = await resp.json() return pokemon['name'] async def main(): async with aiohttp.ClientSession() as session: tasks = [] for number in range(1, 151): url = f'https://pokeapi.co/api/v2/pokemon/{number}' tasks.append(asyncio.ensure_future(get_pokemon(session, url))) original_pokemon = await asyncio.gather(*tasks) for pokemon in original_pokemon: print(pokemon) asyncio.run(main()) print("--- %s seconds ---" % (time.time() - start_time))