1
私はPythonの新しい(ish)asyncio
のものを使ってイベントループを伝統的なスレッドと組み合わせようとしています。私はイベントループを独自のスレッドで実行し、それを分離し、そのループでコルーチンを実行して結果を返す(同期)メソッドを提供するクラスを作成しました。 (これは、すべてがシリアライズする必要があるため、これはやや意味のない例になりますが、それは概念の証明と同様です)。 独自のスレッド内でイベントループを実行する
import asyncio
import aiohttp
from threading import Thread
class Fetcher(object):
def __init__(self):
self._loop = asyncio.new_event_loop()
# FIXME Do I need this? It works either way...
#asyncio.set_event_loop(self._loop)
self._session = aiohttp.ClientSession(loop=self._loop)
self._thread = Thread(target=self._loop.run_forever)
self._thread.start()
def __enter__(self):
return self
def __exit__(self, *e):
self._session.close()
self._loop.call_soon_threadsafe(self._loop.stop)
self._thread.join()
self._loop.close()
def __call__(self, url:str) -> str:
# FIXME Can I not get a future from some method of the loop?
future = asyncio.run_coroutine_threadsafe(self._get_response(url), self._loop)
return future.result()
async def _get_response(self, url:str) -> str:
async with self._session.get(url) as response:
assert response.status == 200
return await response.text()
if __name__ == "__main__":
with Fetcher() as fetcher:
while True:
x = input("> ")
if x.lower() == "exit":
break
try:
print(fetcher(x))
except Exception as e:
print(f"WTF? {e.__class__.__name__}")
は、
asynchio.set_event_loop
の目的は何である「コードレビュー」質問のようにあまりにも多くの響きこれを避けるために、私はそれは、上記に必要なのですか?それはうまく動作します。さらに、コルーチンを呼び出して将来を返すループレベルのメソッドがありますか?これをモジュールレベルの関数で行うのはちょっと奇妙なようです。
「コンテキスト」とはどういう意味ですか?同じスコープ内に複数のループがあった場合を除いて、 'set_event_loop'をどこでも呼び出す必要がないので、"スコープ "を意味することはできません。 'set_event_loop'を' get_event_loop'の欠如にかかわらず使用することは良い考えですか?後者がコードベースのどこかで呼び出された場合に備えてですか? – Xophmeister
これは使用するポリシーに応じて異なりますが、[デフォルトのポリシーでは現在のスレッドとしてコンテキストが定義されています](https://docs.python.org/3/library/asyncio-eventloops.html#event-loop-policies-and - デフォルト - ポリシー)。そして、同じループが他の場所で使用される可能性がある場合は、 'set_event_loop'を呼び出す必要があります。 – dirn
デフォルトのポリシーが「スレッドごとのイベントループを管理する」場合、明示的に 'asyncio.new_event_loop()'を呼び出す必要はありませんか?つまり、各スレッドは暗黙のイベントループを持っていますか?同じコンテキスト内で呼び出されたときに 'get_event_loop'によって返されますか? (もちろん、上のコードでは、新しいスレッド*の外側に*新しいループを作成しますが、それは簡単に変更できます) – Xophmeister