2017-07-11 6 views
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の目的は何である「コードレビュー」質問のようにあまりにも多くの響きこれを避けるために、私はそれは、上記に必要なのですか?それはうまく動作します。さらに、コルーチンを呼び出して将来を返すループレベルのメソッドがありますか?これをモジュールレベルの関数で行うのはちょっと奇妙なようです。

答えて

2

get_event_loopをどこにでも呼び出す場合はset_event_loopを使用し、new_event_loopを呼び出したときに作成されたループを返すようにします。現在のコンテキストのイベントループとこのループを設定する必要がある場合docs

から

は、set_event_loop()は、明示的に呼び出さなければなりません。

例のどこにでもget_event_loopを呼び出さないので、set_event_loopの呼び出しを省略できます。

+0

「コンテキスト」とはどういう意味ですか?同じスコープ内に複数のループがあった場合を除いて、 'set_event_loop'をどこでも呼び出す必要がないので、"スコープ "を意味することはできません。 'set_event_loop'を' get_event_loop'の欠如にかかわらず使用することは良い考えですか?後者がコードベースのどこかで呼び出された場合に備えてですか? – Xophmeister

+0

これは使用するポリシーに応じて異なりますが、[デフォルトのポリシーでは現在のスレッドとしてコンテキストが定義されています](https://docs.python.org/3/library/asyncio-eventloops.html#event-loop-policies-and - デフォルト - ポリシー)。そして、同じループが他の場所で使用される可能性がある場合は、 'set_event_loop'を呼び出す必要があります。 – dirn

+0

デフォルトのポリシーが「スレッドごとのイベントループを管理する」場合、明示的に 'asyncio.new_event_loop()'を呼び出す必要はありませんか?つまり、各スレッドは暗黙のイベントループを持っていますか?同じコンテキスト内で呼び出されたときに 'get_event_loop'によって返されますか? (もちろん、上のコードでは、新しいスレッド*の外側に*新しいループを作成しますが、それは簡単に変更できます) – Xophmeister

関連する問題