AIOHTTP Client デモ

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}")