[英]Call an async function in an normal function
I'm pretty new to the asyncio for python 3.6 我对python 3.6的asyncio很新
So the thing is I have a class and I want to init some property in there. 所以问题是我有一个类,我想在那里初始化一些属性。 And one of the property is the return value from an async function.
其中一个属性是异步函数的返回值。
What's the best practice to do this? 这样做的最佳做法是什么?
Call event_loop one time in the init function to get the return value? 在init函数中调用event_loop一次以获取返回值?
Make the __init__ function async? 使__init__函数异步? and run it in the event loop?
并在事件循环中运行它?
Cheers! 干杯!
Following is my code: 以下是我的代码:
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()
Call event_loop one time in the init function to get the return value?
在init函数中调用event_loop一次以获取返回值?
If you spin the event loop during __init__
, you won't be able to instantiate C
while the event loop is running; 如果在
__init__
期间旋转事件循环,则在事件循环运行时将无法实例化C
; asyncio event loops don't nest . asyncio事件循环不嵌套 。
[ EDIT: After the second update to the question, it appears that the event loop gets run by a non-static method C.run
, so run_until_complete
in __init__
will work with the code as written. [ 编辑:在问题的第二次更新之后,事件循环似乎由非静态方法
C.run
,因此__init__
run_until_complete
将与编写的代码一起使用。 But that design is limited - for example it doesn't allow constructing another instance of C
or of a class like C
while the event loop is running.] 但是这种设计是有限的 - 例如,它不允许在事件循环运行时构造
C
或类C
另一个实例。
Make the
__init__
function async?使
__init__
函数异步? and run it in the event loop?并在事件循环中运行它?
__init__
cannot be made async without resorting to very ugly hacks. 如果不诉诸非常丑陋的黑客,
__init__
不能异步。 Python's __init__
operates by side effect and must return None
, whereas an async def
function returns a coroutine object. Python的
__init__
按副作用运行,必须返回None
,而async def
函数返回一个协程对象。
To make this work, you have several options: 要使这项工作,你有几个选择:
C
factory C
工厂 Create an async function that returns C
instances, such as: 创建一个返回
C
实例的异步函数,例如:
async def make_c():
c = C()
await c._async_init()
return c
Such a function can be async without problems, and can await as needed. 这样的函数可以没有问题地异步,并且可以根据需要等待。 If you prefer static methods to functions, or if you feel uncomfortable accessing private methods from a function not defined in the class, you can replace
make_c()
with a C.create()
. 如果您更喜欢静态方法到函数,或者如果您感觉不舒服从类中未定义的函数访问私有方法,则可以使用
make_c()
替换C.create()
。
Cr
field Cr
字段 You can make the r
property asynchronous, simply by storing a Future
inside of it: 你可以简单地通过在其中存储
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'))
This will require every use of cr
to be spelled as await cr
. 这将要求每次使用
cr
拼写为await cr
。 Whether that is acceptable (or even beneficial) will depend on where and how often it is used elsewhere in the program. 这是否可接受(或甚至是有益的)取决于程序中其他地方使用的位置和频率。
C
constructor C
构造函数 Although __init__
cannot be made async, this limitation doesn't apply to its low-level cousin __new__
. 虽然
__init__
不能异步,但这个限制并不适用于它的低级表亲__new__
。 T.__new__
may return any object, including one that is not even an instance of T
, a fact we can use to allow it to return a coroutine object: 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())
This last approach is something I wouldn't recommend for production code, unless you have a really good reason to use it. 最后一种方法是我不建议用于生产代码的,除非你有充分的理由使用它。
C.__new__
constructor that doesn't bother to return a C
instance; C
实例的C.__new__
构造函数; C.__init__
even if you define or inherit its (sync) implementation; C.__init__
; await C()
looks very non-idiomatic, even (or especially) to someone used to asyncio. await C()
看起来非惯用,甚至(或特别)对于习惯于asyncio的人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.