为什么我需要等待协程?
Why do I need to await for a coroutine?
我从 websockets 开始,asyncio
很难理解背后的逻辑。我过去在 Python 上使用线程,在 Javascript 上使用 AJAX 调用(所以我对多线程的概念(I/O 绑定)和调用异步处理结果的程序)。
示例服务器如下。我的目标是提供一个 websocket 连接和两个每 10 秒调用一次的函数,而无需等待结果(所以每 10 秒调用一次,无论函数处理需要多长时间)。
import time
import arrow
import websockets
import asyncio
async def time1(websocket):
# simulation of a time intensive operation
time.sleep(2)
msg = '1 ' + arrow.now()
print(msg)
websocket.send(msg)
async def time2(websocket):
# simulation of a time intensive operation
time.sleep(3)
msg = '2 ' + arrow.now()
print(msg)
websocket.send(msg)
async def update_info(websocket, path):
while True:
now = arrow.now()
if not now.second % 10:
time1(websocket)
if not now.second % 10:
time2(websocket)
time.sleep(1)
start_server = websockets.serve(update_info, 'localhost', 5678)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
我希望在客户端连接后,在接下来的整整 10 秒内触发功能。它们将在 2 秒和 3 秒后完成,然后在下一个完整的 10 秒等时被解雇。
我得到的是
D:/Dropbox/dev/domotique/webserver.py:708: RuntimeWarning: coroutine 'time1' was never awaited
time1(websocket)
D:/Dropbox/dev/domotique/webserver.py:710: RuntimeWarning: coroutine 'time2' was never awaited
time2(websocket)
和 none 条消息已发送或打印。
为什么我必须 await
协程?我想从 update_info
中启动它们并忘记它们(= 将它们留给它们处理并让它们通过 websocket 发送数据)。 我的方法有什么问题?
await
有效地将等待的协程耦合到事件循环,等待它完成,然后继续。如果您不 await
协程,则不会发生这种情况。
如果你只想 运行 在后台运行一个协程(更像是一个 Task
)然后使用 asyncio.ensure_future(my_coroutine())
,这将衍生出一个 Task
和让您继续其他项目。
编辑:异步新手的一个陷阱是,如果你有多个 运行ning 任务,那么除非任务有内部 await
语句,否则事件循环将被该任务卡住,除非它returns。事件循环给人一种同时做两件事的印象的方式是在不同的代码位之间来回切换。 await
语句是事件循环可以进行处理的点。因此,当一段代码正在等待时,另一段代码将继续 运行。一旦另一段代码命中 await
,则队列中的下一段代码将获得批准,等等。换句话说,请注意放置 awaits
的位置,并以这样一种方式设计您的代码,即长 运行ning 位代码不会阻止受益于异步的更多动态组件。
我从 websockets 开始,asyncio
很难理解背后的逻辑。我过去在 Python 上使用线程,在 Javascript 上使用 AJAX 调用(所以我对多线程的概念(I/O 绑定)和调用异步处理结果的程序)。
示例服务器如下。我的目标是提供一个 websocket 连接和两个每 10 秒调用一次的函数,而无需等待结果(所以每 10 秒调用一次,无论函数处理需要多长时间)。
import time
import arrow
import websockets
import asyncio
async def time1(websocket):
# simulation of a time intensive operation
time.sleep(2)
msg = '1 ' + arrow.now()
print(msg)
websocket.send(msg)
async def time2(websocket):
# simulation of a time intensive operation
time.sleep(3)
msg = '2 ' + arrow.now()
print(msg)
websocket.send(msg)
async def update_info(websocket, path):
while True:
now = arrow.now()
if not now.second % 10:
time1(websocket)
if not now.second % 10:
time2(websocket)
time.sleep(1)
start_server = websockets.serve(update_info, 'localhost', 5678)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
我希望在客户端连接后,在接下来的整整 10 秒内触发功能。它们将在 2 秒和 3 秒后完成,然后在下一个完整的 10 秒等时被解雇。
我得到的是
D:/Dropbox/dev/domotique/webserver.py:708: RuntimeWarning: coroutine 'time1' was never awaited
time1(websocket)
D:/Dropbox/dev/domotique/webserver.py:710: RuntimeWarning: coroutine 'time2' was never awaited
time2(websocket)
和 none 条消息已发送或打印。
为什么我必须 await
协程?我想从 update_info
中启动它们并忘记它们(= 将它们留给它们处理并让它们通过 websocket 发送数据)。 我的方法有什么问题?
await
有效地将等待的协程耦合到事件循环,等待它完成,然后继续。如果您不 await
协程,则不会发生这种情况。
如果你只想 运行 在后台运行一个协程(更像是一个 Task
)然后使用 asyncio.ensure_future(my_coroutine())
,这将衍生出一个 Task
和让您继续其他项目。
编辑:异步新手的一个陷阱是,如果你有多个 运行ning 任务,那么除非任务有内部 await
语句,否则事件循环将被该任务卡住,除非它returns。事件循环给人一种同时做两件事的印象的方式是在不同的代码位之间来回切换。 await
语句是事件循环可以进行处理的点。因此,当一段代码正在等待时,另一段代码将继续 运行。一旦另一段代码命中 await
,则队列中的下一段代码将获得批准,等等。换句话说,请注意放置 awaits
的位置,并以这样一种方式设计您的代码,即长 运行ning 位代码不会阻止受益于异步的更多动态组件。