在普通函数中调用异步函数

时间:2018-03-26 14:47:10

标签: python python-3.x asynchronous python-asyncio

我对asthonio for python 3.6

非常陌生

所以问题是我有一个类,我想在那里初始化一些属性。 其中一个属性是异步函数的返回值。

这样做的最佳做法是什么?

  1. 在init函数中调用event_loop一次以获取返回值?

  2. 使__init__函数异步?并在事件循环中运行它?

  3. 干杯!

    再次更新:

    以下是我的代码:

    import asyncio
    import aioredis
    from datetime import datetime
    
    class C:
        def __init__(self):
            self.a = 1
            self.b = 2
            self.r = None
            asyncio.get_event_loop().run_until_complete(self._async_init())
    
        async def _async_init(self):
            # this is the property I want, which returns from an async function
            self.r = await aioredis.create_redis('redis://localhost:6379')
    
        async def heart_beat(self):
            while True:
                await self.r.publish('test_channel', datetime.now().__str__())
                await asyncio.sleep(10)
    
        def run(self):
            asyncio.get_event_loop().run_until_complete(self.heart_beat())
    
    c=C()
    c.run()
    

1 个答案:

答案 0 :(得分:4)

  

在init函数中调用event_loop一次以获取返回值?

如果在__init__期间旋转事件循环,则在事件循环运行时您无法实例化C; asyncio事件循环don't nest

[编辑:在对问题进行第二次更新后,事件循环似乎由非静态方法C.run运行,因此run_until_complete位于{{ 1}}将使用编写的代码。但是这种设计是有限的 - 例如,当事件循环运行时,它不允许构建 __init__的另一个实例或类似C的类。] < / p>

  

使C函数异步?并在事件循环中运行它?

如果不诉诸非常丑陋的黑客,

__init__就无法变得异步。 Python的__init__由副作用操作,必须返回__init__,而None函数返回一个协程对象。

为了完成这项工作,您有以下几种选择:

异步async def工厂

创建一个返回C个实例的异步函数,例如:

C

这样的函数可以没有问题地异步,并且可以根据需要等待。如果您更喜欢静态方法到函数,或者如果您觉得从类中未定义的函数访问私有方法感到不舒服,可以将async def make_c(): c = C() await c._async_init() return c 替换为make_c()

异步C.create()字段

您可以使C.r属性异步,只需在其中存储r

Future

这需要将<{>每个使用class C: def __init__(self): self.a = 1 self.b = 2 loop = asyncio.get_event_loop() # note: no `await` here: `r` holds an asyncio Task which will # be awaited (and its value accessed when ready) as `await c.r` self.r = loop.create_task(aioredis.create_redis('redis://localhost:6379')) 拼写为c.r。这是否可接受(甚至是有益的)取决于程序中其他地方使用的位置和频率。

异步await c.r构造函数

虽然C无法变为异步,但此限制并不适用于其低级表兄__init____new__可以返回任何对象,包括一个甚至不是T.__new__实例的对象,我们可以使用它来返回一个协程对象:

T

除非你有充分的理由使用它,否则最后一种方法是我不建议用于生产代码的。

  • 这是对构造函数机制的滥用,因为它定义了一个class C: async def __new__(cls): self = super().__new__(cls) self.a = 1 self.b = 2 self.r = await aioredis.create_redis('redis://localhost:6379') return self # usage from another coroutine async def main(): c = await C() # usage from outside the event loop c = loop.run_until_complete(C()) 构造函数,它不会返回C.__new__实例;
  • Python会注意到上述内容,即使您定义或继承其(sync)实现,也会拒绝调用C;
  • 使用C.__init__看起来非惯用,甚至(尤其)对于曾经使用asyncio的人来说。