【问题标题】:How to limit request execution time?如何限制请求执行时间?
【发布时间】:2020-02-04 10:45:54
【问题描述】:

我应该在 3 秒内回复。

我的处理程序与第 3 方服务器对话,它可以在 3 秒内回复或无法回复。

我想到了下面的代码——

class MainReply(webapp2.RequestHandler):
    def get(self):
        # do something
        # start task to talk with 3rd server
        for i in range(300): # wait 3 seconds
            # check task status
            # if finished, then break
            time.sleep(0.01)
        # if not finished, inform user

这是正确的方法吗?还是有更好的解决方案?

更新。我正在开发语音助手机器人(类似于谷歌助手),机器人必须在 3 秒内回复。并且机器人不能自己发起答案,即一旦请求完成,我就不能给出另一个答案。由于这是语音助手,我无法提供链接。我在想下面的方法——如果我能在 3 秒内给出一个正常的答案,那就给它。如果没有 - 请用户用“状态”等简单的词再次询问。

【问题讨论】:

  • 就编程基础而言,我认为这永远不会成为方法。您应该搜索事件订阅和观察者模式,如果语言默认不提供,请检查可用options。
  • @MikeMajara,谢谢,但我认为它不适用于我的情况。假设我订阅了任务完成事件。但它可能发生在 3 秒之前或之后。它将如何提供帮助?我可以在 3 秒内回答用户only。
  • 只在 3 秒内回答用户是什么意思?如果答案在
  • Else - 返回另一个答案。

标签: python python-2.7 google-app-engine task


【解决方案1】:

基本规则是你永远不应该像你的帖子中描述的那样做一个池,因为(1)你“手动”阻塞了比需要更多的资源(2)你弄乱了你的代码来模拟实际上不是的异步代码,以及(3)语言通常提供处理并发编程的工具,这些工具专门用于此类任务,并且比您实现它(在大多数情况下)为您完成的工作要好得多。

遵循您的要求。我写了一个可以测试的简单程序。检查here 以获取asyncio.wait_for 文档。查找 here 以及一些有用的异步指南。

将代码复制到文件中并运行$ python [filename]

import asyncio
import random
from concurrent.futures._base import TimeoutError

async def safe_get():
    result = "I'm currently out of my office."
    try:
        result = await asyncio.wait_for(get(), 3)
    except TimeoutError as e:
        print("Responder thought too much about his answer")
    return result

async def get(a=1,b=6):
    random_time = random.randint(a,b)
    await asyncio.sleep(random_time)
    return "I'm doing good thanks! Sorry it took me " + str(random_time) + "s to answer."

async def main():
    # Toggle comment on the two following lines to see (1) unwanted behaviour and (2) wanted behaviour
    # response = await get()
    response = await safe_get()
    print(response)

if __name__ == "__main__":
    asyncio.run(main())

【讨论】:

  • 谢谢。但恐怕它不适用于 Google App Engine……但这里有一个选项 - cloud.google.com/appengine/docs/standard/python/…
  • 所以不行,为什么?我一定错过了什么。您发送的链接声明“要发出异步请求,您的应用程序必须:...”并且您还可以在其中找到说明,告诉您如何在请求中设置超时。我无法运行 google-api 代码,但在我看来非常相似。你能帮我指出什么是不可能的吗?
  • 对不起,我一开始没有提到我使用的是 Python 2.7。这是它不起作用的确认 - stackoverflow.com/questions/53719006/…。
  • 是什么阻止您使用answer 中的代码sn-p 到该帖子,以及urlfetch.create_rpc() 中所述urlfetch.create_rpc() 中的deadline 参数docs?
【解决方案2】:

除了有问题的用户体验 - 响应缓慢并且可能不是您的用户正在等待的响应 - 这种方法会为您的服务器的完整性带来风险:对于每个待处理的请求,您的服务器将使用资源,并且在高传入的情况下请求高峰,它可能会在其可用池或资源(如果有限)上运行,也可能会增加您的成本(例如,如果配置为自动扩展,则通过启动其他实例来跟上其他传入请求)。

一般来说,对于可能需要很长时间的请求,最好立即回复一个待处理请求的 ID 和一个补充 URL,在这些 URL 中,客户端可以检查请求状态并最终获得预期的响应(如果可用)。您的服务器会注意 - 在后台,而不是在原始传入请求线程中 - 从第 3 方服务器获取答案。通过这种方式,您可以处理任何类型的请求,这些请求可能需要很长时间才能获得答案,无论是来自第三方还是来自内部处理。

【讨论】:

  • 谢谢,丹。让我给你更多细节 - 我正在开发语音助手机器人(类似于谷歌助手),机器人必须在 3 秒内回复。并且机器人不能自己发起答案,即一旦请求完成,我就不能给出另一个答案。由于这是语音助手,我无法提供链接。我在想下面的方法——如果我能在 3 秒内给出一个正常的答案,那就给它。如果没有 - 请用户用“状态”等简单的词再次询问。
【解决方案3】:

您是否通过 http 与该第 3 方服务器通信?你能在 python-requests 中使用timeout 参数吗?

class MainReply(webapp2.RequestHandler):
    def get(self):
        # do something
        try:
            r = requests.post(... , timeout=3)
            # finished, inform user
        except requests.exceptions.Timeout:
            # not finished, inform user

【讨论】:

    猜你喜欢
    • 2011-02-26
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 2018-04-23
    • 2018-06-19
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    相关资源
    最近更新 更多