【问题标题】:Python async await not waitingPython异步等待不等待
【发布时间】:2021-12-05 13:29:40
【问题描述】:

我对异步 python 的工作不多,但目前我有一个使用 Sanic 框架的项目。有 websocket 端点,它从客户端接收数据,向客户端发送消息,该任务已启动,然后运行长同步任务(没有使其异步的选项),最后向客户端发送消息,该任务已完成。有一些示例代码:

from sanic import Sanic
from sanic.server.protocols.websocket_protocol import WebSocketProtocol

app = Sanic("TestApp")

@app.websocket("/")
async def process_task(request, ws: WebSocketServerProtocol):
    raw_data = await ws.recv()
    data = json.loads(raw_data)
    await ws.send("TASK STARTED")
    process_long_task(data) # Long sync function
    await ws.send("TASK ENDED")

但是有一个问题。函数不等待 ws.send("TASK STARTED")。实际上,这两条消息仅在 process_long_task 完成后才发送。虽然,如果我在 await ws.send("TASK STARTED") 之后添加 await asyncio.sleep(0.1) ,它会正常工作

谁能指出我的代码有什么问题?

【问题讨论】:

  • 您期望它应该等待什么?通过网络发送一些数据通常意味着将数据写入缓冲区。操作系统将负责通过任何类型的网络实际发送它。除非缓冲区已满,否则没有理由等待。
  • 听起来很合理,但是我能做些什么来确保在 process_long_task 执行之前发送消息?
  • 除非对方以某种方式回应,否则恐怕你能做的很少,你永远也不知道数据是否已经到达对方。主要问题是你为什么需要这个?
  • FWIW,阅读有关刷新套接字的信息:stackoverflow.com/questions/855544/…
  • 这里是 Sanic 维护者。你用的是什么版本?

标签: python python-asyncio sanic


【解决方案1】:

如果您从协程调用同步函数,则整个循环以及在其中运行的所有任务都将等待该单个同步函数完成。

如果你需要一个长时间运行的同步函数,并且异步等待结果,有几种方法,大多数人使用某种后台线程。

这是一个异步使用socket.gethostbyaddr()(有时完成同步功能很慢)的示例。

async def GetHostFromAddr(ip):
    """
    GetHostFromAddr(ip) -> fqdn\n
    :param ip: The hosts ip address ie. 192.168.1.1
    :return: Return the fqdn (a string of the form 'sub.example.com') for a host.
    """
    loop = asyncio.get_event_loop()
    event = asyncio.Event()
    pool = ThreadPool(processes=1)

    thread_result = pool.apply_async(gethostbyaddr, (ip,), callback=lambda x: loop.call_soon_threadsafe(event.set))

    with contextlib.suppress(asyncio.TimeoutError):
        if await asyncio.wait_for(event.wait(), 5):
            event.clear()
            return thread_result.get()[0]
        else:
            event.clear()
            pool.terminate()

【讨论】:

  • 谢谢。我终于明白了,并通过将长时间运行的任务移至 Celery 解决了我的问题。
猜你喜欢
  • 2016-07-07
  • 2016-03-25
  • 2017-10-09
  • 2017-12-11
  • 2019-05-10
  • 1970-01-01
  • 2020-10-04
相关资源
最近更新 更多