次のコードを使用asyncio
しaiohttp
て、非同期HTTPリクエストを作成します。
import sys
import asyncio
import aiohttp
@asyncio.coroutine
def get(url):
try:
print('GET %s' % url)
resp = yield from aiohttp.request('GET', url)
except Exception as e:
raise Exception("%s has error '%s'" % (url, e))
else:
if resp.status >= 400:
raise Exception("%s has error '%s: %s'" % (url, resp.status, resp.reason))
return (yield from resp.text())
@asyncio.coroutine
def fill_data(run):
url = 'http://www.google.com/%s' % run['name']
run['data'] = yield from get(url)
def get_runs():
runs = [ {'name': 'one'}, {'name': 'two'} ]
loop = asyncio.get_event_loop()
task = asyncio.wait([fill_data(r) for r in runs])
loop.run_until_complete(task)
return runs
try:
get_runs()
except Exception as e:
print(repr(e))
sys.exit(1)
何らかの理由で、get
関数内で発生した例外はキャッチされません。
Future/Task exception was never retrieved
Traceback (most recent call last):
File "site-packages/asyncio/tasks.py", line 236, in _step
result = coro.send(value)
File "mwe.py", line 25, in fill_data
run['data'] = yield from get(url)
File "mwe.py", line 17, in get
raise Exception("%s has error '%s: %s'" % (url, resp.status, resp.reason))
Exception: http://www.google.com/two has error '404: Not Found'
では、クールーチンによって発生した例外を処理する正しい方法は何ですか?
asyncio.wait
Futures
渡されたものを実際に消費するのではなく、完了するのを待ってからFuture
オブジェクトを返します。
コルーチン
asyncio.wait(futures, *, loop=None, timeout=None, return_when=ALL_COMPLETED)
シーケンスfuturesによって指定されたFuturesとコルーチンオブジェクトが完了するのを待ちます。コルーチンはタスクにラップされます。
Future
(完了、保留中)の2つのセットを返します。
リストyield from
内のアイテムを実際に使用するまでdone
、それらは未使用のままになります。プログラムはフューチャーを消費せずに終了するため、「例外は取得されませんでした」というメッセージが表示されます。
あなたのユースケースでは、asyncio.gather
実際にそれぞれを消費しFuture
、Future
すべての結果を集約した単一を返す(またはException
入力リストでフューチャーによってスローされた最初のものが発生する)を使用する方がおそらく理にかなっています。
def get_runs():
runs = [ {'name': 'one'}, {'name': 'two'} ]
loop = asyncio.get_event_loop()
tasks = asyncio.gather(*[fill_data(r) for r in runs])
loop.run_until_complete(tasks)
return runs
出力:
GET http://www.google.com/two
GET http://www.google.com/one
Exception("http://www.google.com/one has error '404: Not Found'",)
フューチャのasyncio.gather
1つが例外を発生させたときに、実際にその動作をカスタマイズできることに注意してください。デフォルトの動作では、最初に発生した例外が発生しますが、出力リストで各例外オブジェクトを返すこともできます。
asyncio.gather(*coros_or_futures, loop=None, return_exceptions=False)
指定されたコルーチンオブジェクトまたは先物からフューチャーアグリゲーション結果を返します。
すべての先物は同じイベントループを共有する必要があります。すべてのタスクが正常に完了した場合、返されるfutureの結果は結果のリストです(元のシーケンスの順序で、必ずしも結果の到着順ではありません)。場合
return_exceptions
でTrue
、作業中の例外が成功した結果と同じように扱われ、結果リストに集まっています。それ以外の場合、最初に発生した例外は、返されたフューチャーにすぐに伝達されます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加