在自己的线程中运行事件循环

Xop*_*ter 5 python python-multithreading python-asyncio

我正在玩 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__}")
Run Code Online (Sandbox Code Playgroud)

为了避免这听起来太像“代码审查”问题,上面的目的是asynchio.set_event_loop什么,我是否需要它?有和没有它都可以正常工作。此外,是否有循环级方法来调用协程并返回未来?使用模块级函数来做到这一点似乎有点奇怪。

dir*_*irn 3

set_event_loop如果您在任何地方调用get_event_loop并希望它返回调用时创建的循环,则需要使用new_event_loop.

\n\n

来自文档

\n\n
\n

如果有\xe2\x80\x99s需要将此循环设置为当前上下文的事件循环,则set_event_loop()必须显式调用。

\n
\n\n

get_event_loop由于您在示例中没有调用任何地方,因此可以省略对 的调用set_event_loop

\n