【问题标题】:Why does Google App Engine support a single thread of execution only?为什么 Google App Engine 只支持单线程执行?
【发布时间】:2020-10-23 00:03:23
【问题描述】:

有人知道为什么 Google App Engine 只允许一个已部署的应用程序执行一个线程吗?

我个人认为这与应用程序的可预测性有关,因此 Google 可以更可靠地调整其性能。 Google 的网站上似乎没有发布任何关于单线程执行的理由,因此我提出了问题。

拥有一个已经是多线程且目前部署在 VM 上的应用程序意味着鉴于此限制,我很难迁移到云端。

编辑:我在下面标记了答案,因为由于水平缩放要求而不允许线程听起来很合理。自然,线程都在同一个进程空间内执行,因为 GAE 可以为您的应用程序运行许多进程,所以很难共享线程。也就是说,我仍然认为每个进程的小线程池会很有用,并且可能有助于将应用程序迁移到云中。我将要求这是一个功能。感谢讨论!

【问题讨论】:

    标签: multithreading google-app-engine concurrency


    【解决方案1】:

    在 Google App Engine 中生成线程的方法有限,称为任务队列:http://code.google.com/appengine/docs/python/taskqueue/

    编辑

    来自http://code.google.com/appengine/docs/java/runtime.html#The_Sandbox

    允许 App Engine 分发 对应用程序的请求 多个网络服务器,并防止 一项应用程序免受干扰 另一个,应用程序运行在一个 受限的“沙盒”环境。在 这种环境下,应用程序可以 执行代码,存储和查询数据 App Engine 数据存储区,使用 App 引擎邮件、URL 获取和用户 服务,并检查用户的网络 请求并准备响应。

    就像其他人指出的那样,出于安全原因,沙盒应用程序不支持线程。

    Google App Engine 中还有许多其他限制迫使开发人员创建可扩展的应用程序。我相信任务队列只是这些限制中的另一个,因为与在处理 HTTP 请求的当前机器上创建线程相反,任务被放入队列中,然后可以在其他机器上调度和执行。任务队列允许以可扩展的方式在机器之间共享和分发工作。

    【讨论】:

    • 任务只是比实现共享队列更高级别的抽象。我仍然有兴趣了解为什么不直接支持线程。
    • 好吧,这听起来很合理——可能是水平缩放方面的考虑……我想的越多,它就越有意义。但是我不太确定安全问题是否有效......水平缩放答案+1。
    • 创建线程可能与安全性有何关系?唯一的安全方面是通过产生太多线程来杀死服务器。所有其他安全参数都是无效的,我可以在一个线程中做的任何事情我都可以在另一个线程中做得同样好。我当然是在谈论简单的任务,而不是 SETI。
    【解决方案2】:

    App Engine 使用基于请求的执行模型 - 也就是说,所有工作都限定为一个请求,无论是面向用户的一个请求,还是由另一个系统(例如任务队列)发起的一个请求。虽然可以在这种环境中使用线程,但大多数使用多线程的用例都涉及长时间运行的进程,App Engine 不是为这些进程设计的,或者离线工作,在这种情况下你会更好使用 App Engine 提供的可扩展设施,例如任务队列。

    换句话说,线程是针对一般问题的特定解决方案。 App Engine 以任务队列的形式为大多数用例提供了替代方案。

    【讨论】:

    • 感谢您提供额外的视角。我仍然认为这不是真正的原因。 GAE 可能无论如何都会限制您的请求必须处理的时间量,并且可以很容易地将约束应用于线程池中线程的运行时间。不过还是谢谢。
    • 你可以,但是在那种情况下你为什么要使用线程池呢?您必须为每个请求启动一个新请求。
    【解决方案3】:

    我认为这是一个误导性的问题。 App Engine 不允许您的应用程序生成线程,但应用程序引擎可能会启动您的应用程序的多个实例或使用某种线程或多进程请求处理程序。我不知道具体细节,但如果没有某种并行性,应用引擎将是一个毫无用处的平台。

    编辑

    我最初的回答错误地暗示线程不是一个有用的功能,它们有很多用途,但大多数 Web 开发人员并不在他们的应用程序中管理线程。线程通常在应用程序堆栈的较低级别进行管理。

    【讨论】:

    • 让我们假设已经接受了在应用程序中拥有多个线程是一件好事。例如,我的应用程序接收 RESTful 请求,将其发布到队列,该队列有多个消费者等。其他类型的请求可能会进入队列 - 不仅仅是来自 HTTP。
    • 那么您是说,GAE 不支持线程,因为它们对人们来说太难理解了?听起来像是 Apple 对 IoS 很苛刻的论点……直到他们得知程序员实际上对他们没意见。我不认为这是 GAE 只支持一个执行线程的原因......仅仅因为它们在那里并不意味着你当然必须使用它们。
    • @Christopher Hunt,我没有说线程难以理解,你只是在编造。如果您对 Web 开发人员进行随机调查,那么在他们的应用程序中明确管理线程的百分比将会很小。 Google 无法打造一个让所有人都满意的平台,因此他们决定不迎合需要此功能的少数开发人员。请记住,这是 App Engine 的众多限制之一,很抱歉 AE 不能满足您的需求,但不要假设您的需求与其他人的需求相同。
    • 如果您可以支持这一点,“并决定他们不会迎合需要此功能的少数开发人员”,那么我会将您的回复视为答案。
    • @Christopher 您描述的用例完全适合 App Engine 已经提供的任务队列。您是否有一个令人信服的 App Engine 线程用例,它不能作为任务队列更好地工作?
    【解决方案4】:

    我不确定,但我相信这可能是出于安全原因。如果它们允许多个线程,它们就会为fork() 炸弹(或线程等效项)敞开大门。此外,它还大大简化了资源管理 - Google 只需要管理每个应用程序的单个线程资源。

    【讨论】:

    • 我认为您可能对资源管理有所了解。但是,无论您只允许一个线程还是十个线程,您仍然可以通过线程池进行管理。
    【解决方案5】:

    自提出此问题以来推出的一项新功能是background threads

    虽然在给定请求结束时加入常规线程(它们不能比请求长),但后台线程没有此限制。

    后台线程

    在手动或基本扩展实例上运行的代码可以启动一个后台线程,该线程可以比产生它的请求更长。这允许实例执行任意定期或计划任务,或在请求返回给用户后继续在后台工作。

    示例代码:

    from google.appengine.api import background_thread
    
    # sample function to run in a background thread
    def change_val(arg):
        global val
        val = arg
    
    if auto:
        # Start the new thread in one command
        background_thread.start_new_background_thread(change_val, ['Cat'])
    else:
        # create a new thread and start it
        t = background_thread.BackgroundThread(
            target=change_val, args=['Cat'])
        t.start()
    

    【讨论】:

      【解决方案6】:

      Google Flexible App Engine 可以在 Docker 容器中运行任何可执行文件。您可以 Dockerize 多线程可执行文件并将其部署在 Flexibile App Engine 上。我已经完成了这项工作并按预期工作。

      【讨论】:

        猜你喜欢
        • 2012-12-29
        • 1970-01-01
        • 2012-12-17
        • 1970-01-01
        • 1970-01-01
        • 2012-10-19
        • 2017-03-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多