繁体   English   中英

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

[英]Call an async function in an normal function

我对python 3.6的asyncio很新

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

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

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

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

干杯!

再次更新:

以下是我的代码:

 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() 

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

如果在__init__期间旋转事件循环,则在事件循环运行时将无法实例化C ; asyncio事件循环不嵌套

[ 编辑:在问题的第二次更新之后,事件循环似乎由非静态方法C.run ,因此__init__ run_until_complete将与编写的代码一起使用。 但是这种设计是有限的 - 例如,它不允许在事件循环运行时构造C或类C 另一个实例。

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

如果不诉诸非常丑陋的黑客, __init__不能异步。 Python的__init__按副作用运行,必须返回None ,而async def函数返回一个协程对象。

要使这项工作,你有几个选择:

异步C工厂

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

async def make_c():
    c = C()
    await c._async_init()
    return c

这样的函数可以没有问题地异步,并且可以根据需要等待。 如果您更喜欢静态方法到函数,或者如果您感觉不舒服从类中未定义的函数访问私有方法,则可以使用make_c()替换C.create()

异步Cr字段

你可以简单地通过在其中存储Future来使r属性异步:

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'))

这将要求每次使用cr拼写为await cr 这是否可接受(或甚至是有益的)取决于程序中其他地方使用的位置和频率。

异步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实例的C.__new__构造函数;
  • Python将注意到上述内容,即使您定义或继承其(sync)实现,也将拒绝调用C.__init__ ;
  • 使用await C()看起来非惯用,甚至(或特别)对于习惯于asyncio的人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM