Pyhonで非同期処理を考える。
まずは"asyncio"を使った処理を考えていきます。Colabを使って実行していこうと思って少しコードを試したときに、エラーが出た時の対処法です。
を参考に
import nest_asyncio
nest_asyncio.apply()
を付け加えればうまくエラーなしで実行されるようになります。
参考
juputerで動かすときの注意点:Colabでも上記の対応以外にこの方法が使えます
"asyncio"の使い所
その他、上記サイトでは具体的な使い方として以下紹介されています。
まず基本的なところですが
import asyncio
async def main():
print('Hello ...')
await asyncio.sleep(1)
print('... World!')
asyncio.run(main())
を実行すると'Hello ...'が出てきて1秒後に'... World!'が出てきます。
で1秒間待ってから次が実行されます。
他の機能として、sleep、gather、create_task / Task、Task.result、Task.done、TaskGroup、Lock、Semaphore、Event、Queue、PriorityQueue
などサンプルコードをあげて紹介されています。
次にこちらのサイトのコードを使わせていただきColabで実行してみてasyncioの効果を測定します。
まず"requests"を利用してやってみます。
import requests
import time
import pandas as pd
result = []
def get_poke(id):
r = requests.get(f'https://pokeapi.co/api/v2/pokemon/{id}')
result.append([r.json()['id'], r.json()['name']])
def main():
start = time.time()
for poke_id in range(1,152):
get_poke(poke_id)
end = time.time()
print(f"processing time:{end-start}") #処理時間を測定する
main()
print(pd.DataFrame(result,columns=['id','name']).sort_values('id').reset_index(drop=True))
asyncioの効果を測定
実行すると
processing time:25.087804317474365
id name
0 1 bulbasaur
1 2 ivysaur
2 3 venusaur
3 4 charmander
4 5 charmeleon
.. ... ...
146 147 dratini
147 148 dragonair
148 149 dragonite
149 150 mewtwo
150 151 mew
[151 rows x 2 columns]
25秒かかっていることがわかります。
次にasyncio:並行処理でやってみます。
これを実行する前にasyncio版のrequestsである"httpx"を
!pip install httpx
とインストールして以下実行します。
import httpx #asyncio版のrequests
import time
import asyncio
import pandas as pd
result = []
async def get_poke(id):
async with httpx.AsyncClient() as client:
r = await client.get(f'https://pokeapi.co/api/v2/pokemon/{id}')
result.append([r.json()['id'], r.json()['name']])
#コルーチン
async def main():
start = time.time()
tasks = []
#タスクを設定する(151匹分)
for poke_id in range(1,152):
tasks.append(get_poke(poke_id))
#タスク実行
await asyncio.gather(*tasks)
end = time.time()
print(f"processing time:{end-start}") #処理時間を測定する
asyncio.run(main()) #イベントループ作成
print(pd.DataFrame(result,columns=['id','name']).sort_values('id').reset_index(drop=True))
を実行すると
processing time:17.935431003570557
id name
0 1 bulbasaur
1 2 ivysaur
2 3 venusaur
3 4 charmander
4 5 charmeleon
.. ... ...
146 147 dratini
147 148 dragonair
148 149 dragonite
149 150 mewtwo
150 151 mew
[151 rows x 2 columns]
17秒となりました。参考サイトでは3秒となっていましたがColabの環境では少し時間がかかるようですが、asyncioを使うことで短縮できました。