[英]Asyncio python - TypeError: A Future, a coroutine or an awaitable is required
[英]Converting a Python function with a callback to an asyncio awaitable
我想在異步上下文中使用PyAudio
庫,但該庫的主要入口點只有一個基於回調的 API:
import pyaudio
def callback(in_data, frame_count, time_info, status):
# Do something with data
pa = pyaudio.PyAudio()
self.stream = self.pa.open(
stream_callback=callback
)
我希望如何使用它是這樣的:
pa = SOME_ASYNC_COROUTINE()
async def listen():
async for block in pa:
# Do something with block
問題是,我不確定如何將此回調語法轉換為在回調觸發時完成的未來。 在 JavaScript 中,我會使用promise.promisify()
,但 Python 似乎沒有這樣的東西。
由於兩個原因, promisify
的等效promisify
不適用於此用例:
這是一種可能的實現:
def make_iter():
loop = asyncio.get_event_loop()
queue = asyncio.Queue()
def put(*args):
loop.call_soon_threadsafe(queue.put_nowait, args)
async def get():
while True:
yield await queue.get()
return get(), put
make_iter
返回一對<async iterator, put-callback>。 返回的對象包含調用回調會導致迭代器生成其下一個值(傳遞給回調的參數)的屬性。 回調可以從任意線程調用,因此可以安全地傳遞給pyaudio.open
,而異步迭代器應該在 asyncio 協程中提供給async for
,它將在等待下一個值時暫停:
async def main():
stream_get, stream_put = make_iter()
stream = pa.open(stream_callback=stream_put)
stream.start_stream()
async for in_data, frame_count, time_info, status in stream_get:
# ...
asyncio.get_event_loop().run_until_complete(main())
請注意,根據文檔,回調還必須返回一個有意義的值、一個幀元組和一個布爾標志。 這可以通過更改fill
函數來合並到設計中,以便也從 asyncio 端接收數據。 不包括實現,因為如果不了解域,它可能沒有多大意義。
您可能想使用Future
類 asyncio.Future(*, loop=None)¶
Future 表示異步操作的最終結果。 不是線程安全的。
Future 是一個可等待的對象。 協程可以等待 Future 對象,直到它們有結果或異常集,或者直到它們被取消。
通常,Futures 用於啟用基於低級回調的代碼(例如在使用 asyncio 傳輸實現的協議中)以與高級 async/await 代碼互操作。
經驗法則是永遠不要在面向用戶的 API 中公開 Future 對象,推薦的創建 Future 對象的方法是調用 loop.create_future()。 通過這種方式,替代事件循環實現可以注入自己優化的 Future 對象實現。
一個愚蠢的例子:
def my_func(loop):
fut = loop.create_future()
pa.open(
stream_callback=lambda *a, **kw: fut.set_result([a, kw])
)
return fut
async def main(loop):
result = await my_func(loop) # returns a list with args and kwargs
我假設pa.open
在線程或子進程中運行。 如果沒有,您可能還需要使用asyncio.loop.run_in_executor包裝調用以open
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.