簡體   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