RuntimeWarning:从未等待协程。如何异步/等待回调

时间:2019-08-12 12:26:56

标签: python asynchronous python-asyncio asyncpg

我有一个提供网络套接字的类,并收听PostgreSQL。使用asyncpg,当我尝试使用add_listener时,出现错误:RuntimeWarning:从未等待协程。如何异步/等待回调。我尝试添加“ await self.listener”,但是它不起作用。

有没有其他方法可以解决这个问题?

import asyncio
import http
import websockets
import asyncpg

class App(object):

    def __init__(self, loop):
        self.loop = loop
        self.ws_list = []
        self.conn = None

    async def ws_handler(self, ws, path):
        if self.conn is None:
            self.conn = await asyncpg.connect(user='xxx', password='xxx', database='pgws', host='127.0.0.1')
            await self.conn.add_listener('todo_updates', self.listener)
        print('new socket!!!')
        self.ws_list.append(ws)
        while True:
            await asyncio.sleep(1)

    async def listener(self, conn, pid, channel, payload):
        print(payload)
        for ws in self.ws_list:
            task = asyncio.create_task()
            await ws.send(payload)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    app = App(loop)
    start_server = websockets.serve(app.ws_handler, 'localhost', 8766)
    app.loop.run_until_complete(start_server)
    app.loop.run_forever()

1 个答案:

答案 0 :(得分:3)

问题在于您传递给asyncpg.Connection.add_listener()的回调是coroutine function,但它应该是一个简单的同步函数。 asyncpg不会引发错误,因为从技术上讲,它仍然是一个可调用的对象,它需要连接,pid,通道和有效负载,但是它的行为不像您期望的那样。

要从同步回调(在事件循环已在运行)中调用异步函数,您需要使用asyncio.create_task()(在Python> = 3.7中)或loop.create_task()(在Python中) > = 3.4.2)或asyncio.ensure_future()(在Python> = 3.4.4中),如下所示:

class App:
    ...  # Your other code here
    def listener(self, conn, pid, channel, payload):
        print(payload)
        for ws in self.ws_list:
            asyncio.create_task(ws.send(payload))

请注意,asyncio.create_task()(以及前面提到的其他功能)将立即返回,并且不会等待任务完成。该任务将安排计划在其他一个或多个await之后运行。