异步-同步-在一个python事件循环中异步调用

dmi*_*try 5 python python-3.x python-asyncio aiohttp

假设我有一个内部使用asyncio循环且没有异步接口的类:

class Fetcher:
    _loop = None
    def get_result(...):
        """
        After 3 nested sync calls async tasks are finally called with *run_until_complete*
        """
        ...
Run Code Online (Sandbox Code Playgroud)

我在内部使用asyncio的所有优点,而不必在外部代码中关心它。

但是然后我想Fetcher在一个事件循环中调用3个实例。如果我有async def界面,那就没有问题:asyncio.gather可以帮助我。如果不同时支持两个接口,是否真的没有其他方法可以做到?来吧!它使您由于一次异步使用而更改了所有项目。告诉我这不是真的。

Mik*_*mov 6

来吧!它使您由于一次异步使用而更改了所有项目。告诉我这不是真的。

这是真的 :)

使用await关键字的整个想法是在一个事件循环中从代码的不同位置执行并发作业(这对于常规功能代码是无法做到的)。

asyncio -不是某种实用程序,而是编写异步程序的整体风格。


另一方面,Python非常灵活,因此您仍然可以尝试隐藏asyncio的使用。如果您确实想要获取3个Fetcher实例的同步结果,则可以执行以下操作:

import asyncio


def sync_exec(coro):
    loop = asyncio.get_event_loop()
    return loop.run_until_complete(coro)


class Fetcher:
    async def async_get_result(self):
        # async interface:
        async def async_job():
            await asyncio.sleep(1)
            return id(self)
        return (await async_job())

    def get_result(self):
        # sync interface:
        return sync_exec(self.async_get_result())

    @classmethod
    def get_results(cls, *fetchers):
        # sync interface multiple:
        return sync_exec(
            asyncio.gather(*[fetcher.async_get_result() for fetcher in fetchers])
        )        



# single sync get_result:
f1 = Fetcher()
print('Result: ', f1.get_result())


# multiple sync get_result:
f2 = Fetcher()
f3 = Fetcher()
print('Results: ', Fetcher.get_results(f1, f2, f3))
Run Code Online (Sandbox Code Playgroud)

输出:

Result:  2504097887120
Results:  [2504097887120, 2504104854416, 2504104854136]
Run Code Online (Sandbox Code Playgroud)

但是,再次重申,相信您,如果有一天继续以这种方式编写代码,您将真的后悔。如果要充分利用异步编程的优势,请使用coroutinesawait显式。

  • 但是你只能使用 run_until_complete() 一次,因为 asyncio 不支持嵌套异步调用...如果有多个异步函数,则上述方法将不起作用。 (3认同)
  • 这两个独立的世界,同步和异步,使过渡到异步变得异常复杂:(也许我会在创建完全异步工具后改变主意。无论如何,谢谢您的回答。 (2认同)