2015-09-16 16 views
11

Asyncioとaiohttpライブラリを使用してたくさんのリクエスト(〜1000)を作成しようとしていますが、私は多くの情報を見つけることができないという問題に遭遇しています。Asyncio RuntimeError:イベントループが終了しました

このコードを10個のURLで実行すると、正常に動作します。私は100 + URLでそれを実行すると、それは壊れて、私にRuntimeError: Event loop is closedエラーを与える。

import asyncio 
import aiohttp 


@asyncio.coroutine 
def get_status(url): 
    code = '000' 
    try: 
     res = yield from asyncio.wait_for(aiohttp.request('GET', url), 4) 
     code = res.status 
     res.close() 
    except Exception as e: 
     print(e) 
    print(code) 


if __name__ == "__main__": 
    urls = ['https://google.com/'] * 100 
    coros = [asyncio.Task(get_status(url)) for url in urls] 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(asyncio.wait(coros)) 
    loop.close() 

スタックトレースはhereです。

私はこれ以上数時間頭を叩いていたので、助けや洞察力があれば幸いです。明らかに、これはまだ開いているはずのイベントループがクローズされていることを示唆していますが、その可能性はわかりません。

+0

を行ってください 'Asyncio'エラーではありません。 Pythonの再帰的なエラー、限界に達しました。すべての非クラス関数のスレッドが必要です。 – dsgdfg

+0

まず、最新のaiohttpリリースを使用していることを確認してください。 私はあなたと思っています。 技術的には、基本的なソケットを閉じるための要求を終えた後、ループの繰り返しが1回必要です。 'loop.close()'の前に 'loop.run_until_complete(asyncio.sleep(0))'を挿入してください。 –

+0

あなたのトレースバックは、[Executor](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor)から[run_in_executor](https:// docs .python.org/3/library/asyncio-eventloop.html#asyncio.BaseEventLoop.run_in_executor)がループが閉じられた後に返されました。奇妙なことに、[aiohttp](https://github.com/KeepSafe/aiohttp/search?utf8=%E2%9C%93&q=run_in_executor&type=Code)と[asyncio](https://github.com/python/asyncio)/search?utf8 =%E2%9C%93&q = run_in_executor) 'run_in_executor'を使用しないでください... – Vincent

答えて

3

あなたが正しくて、loop.getaddrinfoThreadPoolExecutorを使用してsocket.getaddrinfoをスレッドで実行します。

asyncio.wait_forタイムアウトを使用しています。つまり、res = yield from asyncio.wait_for...は、4秒後にasyncio.TimeoutErrorになります。次に、get_statusコルーチンはNoneを返し、ループが停止します。その後でジョブが終了すると、イベントループでコールバックをスケジュールしようとし、すでに閉じているので例外が発生します。

+0

ああ、それは意味がありますが、これがリクエストタイムアウトを実装するための唯一の方法です。ループを閉じることなくタイムアウトできる方法を知っていますか? –

+0

@PatrickAllen [ワーカー数](https://github.com/python/asyncio/blob/27f3499f968e8734fef91677eb339b5d32a6f675/asyncio/base_events.py#L44)のデフォルト値は5です。 – Vincent

+2

@PatrickAllenループを閉じる前に 'loop._default_executor.shutdown(wait = True)'を使う。 – Vincent

16

バグがhttps://github.com/python/asyncio/issues/258 として提出されています。

すぐに回避策として、カスタム実行プログラムを使用することをおすすめします。あなたのプログラムを終了する前に

loop = asyncio.get_event_loop() 
executor = concurrent.futures.ThreadPoolExecutor(5) 
loop.set_default_executor(executor) 

executor.shutdown(wait=True) 
loop.close() 
+0

あなたの助けてくれてありがとう、Andrew、素晴らしい。私はチームの一部と話していたことに気付かなかった。これに続いて、GH –

+0

がバージョン3.5.3で変更されました。BaseEventLoop.run_in_executor()は、作成するスレッドプールエグゼキュータのmax_workersを設定しません。 ' – RomanPerekhrest

+0

Andrew、Python 3.5では「すばやい回避」ではなく堅牢な回避策を提案できますか? – RomanPerekhrest

関連する問題