在普通函数中调用异步函数
Call an async function in an normal function
我对 python 3.6
的 asyncio 还很陌生
所以问题是我有一个 class,我想在其中初始化一些 属性。
属性 之一是来自异步函数的 return 值。
执行此操作的最佳做法是什么?
在init函数中调用一次event_loop得到return值?
使 __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()
Call event_loop one time in the init function to get the return value?
如果在 __init__
期间旋转事件循环,您将无法在事件循环 运行ning 期间实例化 C
;异步事件循环 don't nest.
[编辑: 在对问题进行第二次更新后,事件循环似乎通过 non-static 方法 C.run
,因此 __init__
中的 run_until_complete
将按照编写的代码工作。但这种设计是有限的——例如,它不允许在事件循环时构造 C
或 class 的 另一个 实例,例如 C
运行宁。]
Make the __init__
function async? and run it in the event loop?
__init__
不借助非常丑陋的 hack 就无法实现异步。 Python 的 __init__
由副作用操作并且必须 return None
,而 async def
函数 return 是协程对象。
要完成这项工作,您有多种选择:
异步C
工厂
创建一个 returns C
个实例的异步函数,例如:
async def make_c():
c = C()
await c._async_init()
return c
这样的函数可以async没有问题,也可以按需等待。如果您更喜欢静态方法而不是函数,或者您觉得从 class 中未定义的函数访问私有方法感到不自在,则可以将 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__
不能异步,但此限制不适用于它的 low-level 堂兄 __new__
。 T.__new__
可以 return 任何对象,包括甚至不是 T
实例的对象,我们可以使用这一事实来允许它 return 协程对象:
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__
构造函数,该构造函数不关心 return 一个 C
实例;
- Python 会注意到上述情况,并且会拒绝调用
C.__init__
,即使您定义或继承了它的(同步)实现;
- 使用
await C()
看起来非常 non-idiomatic,甚至(或尤其是)对于习惯 asyncio 的人来说也是如此。
我对 python 3.6
的 asyncio 还很陌生所以问题是我有一个 class,我想在其中初始化一些 属性。 属性 之一是来自异步函数的 return 值。
执行此操作的最佳做法是什么?
在init函数中调用一次event_loop得到return值?
使 __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()
Call event_loop one time in the init function to get the return value?
如果在 __init__
期间旋转事件循环,您将无法在事件循环 运行ning 期间实例化 C
;异步事件循环 don't nest.
[编辑: 在对问题进行第二次更新后,事件循环似乎通过 non-static 方法 C.run
,因此 __init__
中的 run_until_complete
将按照编写的代码工作。但这种设计是有限的——例如,它不允许在事件循环时构造 C
或 class 的 另一个 实例,例如 C
运行宁。]
Make the
__init__
function async? and run it in the event loop?
__init__
不借助非常丑陋的 hack 就无法实现异步。 Python 的 __init__
由副作用操作并且必须 return None
,而 async def
函数 return 是协程对象。
要完成这项工作,您有多种选择:
异步C
工厂
创建一个 returns C
个实例的异步函数,例如:
async def make_c():
c = C()
await c._async_init()
return c
这样的函数可以async没有问题,也可以按需等待。如果您更喜欢静态方法而不是函数,或者您觉得从 class 中未定义的函数访问私有方法感到不自在,则可以将 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__
不能异步,但此限制不适用于它的 low-level 堂兄 __new__
。 T.__new__
可以 return 任何对象,包括甚至不是 T
实例的对象,我们可以使用这一事实来允许它 return 协程对象:
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__
构造函数,该构造函数不关心 return 一个C
实例; - Python 会注意到上述情况,并且会拒绝调用
C.__init__
,即使您定义或继承了它的(同步)实现; - 使用
await C()
看起来非常 non-idiomatic,甚至(或尤其是)对于习惯 asyncio 的人来说也是如此。