AIOHTTP Client デモ¶
- PokéAPI を使ってポケモンを150匹Getする方法を3つ紹介し処理の速さを比較する
- PokéAPIについて
endpoint: https://pokeapi.co/docs/v2#pokemon
- API例:
https://pokeapi.co/api/v2/pokemon/25 : id 25 の ピカチュウ情報URL
Requests を使った場合¶
Requests を使って通常のHTTPリクエストでAPIへアクセスする
$ pip install requests
1import time
2
3import requests
4import logging
5logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%X")
6
7
8def human_requests():
9 for num in range(1,151):
10 url = f"https://pokeapi.co/api/v2/pokemon/{num}"
11 resp = requests.get(url)
12 if resp.status_code == 200:
13 pokemon = resp.json()
14 logging.info(f"{pokemon['id']}: {pokemon['name']}")
15
16start = time.time()
17human_requests()
18end = time.time()
19logging.info(f"実行結果: time: {end-start}")
実行結果: time: 5.970675468444824
非同期にリクエストをする場合¶
await resp.json()
でbody をjsonで要求。bodyを待っている間に、後続のポケモンURL
jsonが返ってきたら、URLを投げている処理を一旦止めて、ポケモン ID と name を出力
1import time
2import asyncio
3
4import aiohttp
5import logging
6logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%X")
7
8async def main():
9 async with aiohttp.ClientSession() as session:
10 for num in range(1, 151):
11 url = f"https://pokeapi.co/api/v2/pokemon/{num}"
12 async with session.get(url) as resp:
13 pokemon = await resp.json()
14 logging.info(f"{pokemon['id']}: {pokemon['name']}")
15
16
17start = time.time()
18asyncio.run(main())
19end = time.time()
20logging.info(f"実行結果: time: {end-start}")
実行結果: time: 2.4725234508514404
タスクリストを先に作って非同期にリクエストする場合¶
まずは非同期リクエスト用のタスクリストを作成し、 asyncio.create_task へ渡す。
このタスクリストを asyncio.gather へ渡して全てのタスクを並行に実行する。この実行を await して全部完了するまで待つ。返り値の順序は、
create_task
で作った順序と同じ。
1import time
2import asyncio
3import aiohttp
4
5import logging
6
7logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%X")
8
9
10async def get_pokemon(s, url):
11 async with s.get(url) as resp:
12 pokemon = await resp.json()
13 return (pokemon["id"], pokemon["name"])
14
15
16async def main():
17 async with aiohttp.ClientSession() as session:
18 tasks = list()
19 for num in range(1, 151):
20 url = f"https://pokeapi.co/api/v2/pokemon/{num}"
21 tasks.append(asyncio.create_task(get_pokemon(session, url)))
22
23 pokemons = await asyncio.gather(*tasks)
24 for id, pokemon in pokemons:
25 logging.info(f"{id}: {pokemon}")
26
27
28start = time.time()
29asyncio.run(main())
30logging.info("end")
31end = time.time()
32logging.info(f"実行結果: time: {end-start}")
実行結果: time: 0.4347381591796875
返り値の順番は気にせず、通信が終わった順に取得する場合
1import time
2import asyncio
3import aiohttp
4
5import logging
6
7logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%X")
8
9
10async def get_pokemon(s, url):
11 async with s.get(url) as resp:
12 pokemon = await resp.json()
13 return (pokemon["id"], pokemon["name"])
14
15
16async def main():
17 async with aiohttp.ClientSession() as session:
18 tasks = list()
19 for num in range(1, 151):
20 url = f"https://pokeapi.co/api/v2/pokemon/{num}"
21 tasks.append(asyncio.create_task(get_pokemon(session, url)))
22
23 for pokemon in asyncio.as_completed(tasks):
24 results = await pokemon
25 print(results)
26
27
28start = time.time()
29asyncio.run(main())
30logging.info("end")
31end = time.time()
32logging.info(f"実行結果: time: {end-start}")