App Engine 调度程序何时使用新线程与新实例?
Posted
技术标签:
【中文标题】App Engine 调度程序何时使用新线程与新实例?【英文标题】:When does the App Engine scheduler use a new thread vs. a new instance? 【发布时间】:2012-07-16 13:32:45 【问题描述】:如果我在我的 app.yaml
文件中设置 threadsafe: true
,那么管理何时创建新实例来服务请求以及何时在现有实例上创建新线程的规则是什么?
如果我有一个应用程序对每个请求都执行计算密集型操作,那么多线程对我有什么好处吗?换句话说,实例是多核实例还是单核?
或者,是否只有在现有线程等待 IO 时才会启动新线程?
【问题讨论】:
This answer 可能有助于回答您的第一个问题。 Takashi 表示 AE 实例被限制为 10 个并发线程,因此第 11 个线程似乎会启动一个新实例。 +1 在 SO 上公开询问此问题,而不是通过电子邮件发送给您的同事。 【参考方案1】:以下规则集当前用于确定给定实例是否可以接受新请求:
if processing more than N concurrent requests (today N=10): false
elif exceeding the soft memory limit: false
elif exceeding the instance class CPU limit: false
elif warming up: false
else true
以下总 CPU/内核限制当前适用于每个实例类:
CLASS 1: 600MHz 1 core
CLASS 2: 1.2GHz 1 core
CLASS 4: 2.4GHz 1 core
CLASS 8: 4.8GHz 2 core
因此,只有一个 B8
实例可以并行处理多达 2 个完全 CPU 绑定的请求。
为小于 8 的实例类设置 threadsafe: true
(Python) 或 <threadsafe>true</threadsafe>
(Java) 将不允许在单个实例上并行处理多个 CPU 绑定请求。
如果您没有完全受 CPU 限制或进行 I/O,Python 和 Java 运行时将生成新线程来处理新请求,最多 10 个并发请求 threadsafe: true
还要注意,即使 Go 运行时是单线程的,它也支持并发请求: 它将为每个请求生成 1 个 goroutine,并在执行 I/O 时在 goroutine 之间产生控制。
【讨论】:
这仅适用于后端,对吧?对于前端实例,当上述规则均未触发时,我会看到新实例启动。 @KrisGiesing 这也适用于前端,但生成新实例来处理新请求还是在队列中等待的决定也取决于您的性能设置。 @proppy 感谢您回答这个问题。如果新的实例是基于 CPU 和内存来启动的,为什么并发请求限制仍然存在?我虽然 N=10 背后的基本原理是为了防止内存不足错误。是否可以删除 N=10 检查,还是有其他原因? @KrisGiesing 有一个关于此的功能请求,让我们将讨论移至此处:code.google.com/p/googleappengine/issues/detail?id=7927 @proppy 我认为这个问题与我无关。我在说这个:code.google.com/p/googleappengine/issues/detail?id=7910【参考方案2】:阅读 Kyle Finley 建议的来自link 的下一条消息
Jeff Schnitzer:还有 10 个线程的硬性限制吗?
是的,但可能不是您所期望的原因。我们的首要问题 遇到的是内存管理。如果我们将默认值提高到 100,许多 然后应用程序会看到内存不足的死亡(比现在更多),并且 这些死亡对于 python/java/go 的表现不同。正确的道路 forward 是更智能的算法 wrt 内存,提供 可配置性等等。这是一个例子 我们为调度程序工作的项目,但与我们拥有的任何团队一样 优先考虑我们的项目。我建议归档这个(或任何其他 所需的调度程序增强)在公共问题跟踪器上,所以他们 可以获得反馈/数据/投票。
【讨论】:
我认为这是答案的一部分,但它没有解决实例的多/单核心方面。对于有兴趣提高此并发请求限制的任何人,请星标Allow configurable limit of concurrent requests per instance 它也根本没有解决一个实例在创建新实例之前是否需要实际有 10 个活动线程。【参考方案3】:如果我在我的 app.yaml 文件中设置 threadsafe: true,那么管理何时创建新实例来服务请求以及何时在现有实例上创建新线程的规则是什么?
就像人们在这里所说的那样,如果以前的实例已经使用了 10 个线程,则会启动一个带有新线程的新实例。如果所有其他线程都忙,则将创建一个新线程,它们必须等待响应或计算结果。
如果我有一个应用程序对每个请求都执行计算密集型操作,那么多线程对我有什么好处吗?换句话说,实例是多核实例还是单核?
现在这个问题很有争议。每个人都知道答案,但他们仍然持怀疑态度。如果您的任务仅基于计算,那么多线程永远不会给您带来任何好处,除非您使用的是多核处理器,不要问我为什么多核处理器会有更好的帮助,您知道答案。现在谷歌应用引擎还不够复杂,无法决定何时将新线程分派到另一个处理器/核心(如果存在),只有新实例才会分派到另一个核心/处理器。希望您的线程在其他核心/处理器中运行?好吧,在那里扔一些技能,然后嘘!请记住,由您决定线程是否应该在其他内核/处理器中运行,引擎不能对此负责,因为这可能会导致很多混乱,引擎不是上帝。简而言之,默认情况下,实例是单核的,引擎无法为您决定何时应该转为多核。
或者,是否只有在现有线程等待 IO 时才会启动新线程?
我的回答的第一部分清除了这一点。是的,它们仅在现有线程繁忙时才启动,这就是线程安全的工作方式,以防止死锁。
现在我可以告诉你这一切,根据我的个人经验,我在应用程序引擎上工作了好几个月,并且对高度依赖于线程安全架构的应用程序进行了编程/调试/测试。如果你想我可以添加参考(我没有参考,只是个人经验,但我已经准备好为你搜索并把东西放在桌子上),但我认为在这种情况下不需要它们,线程安全以明显的方式工作,我已经验证了自己。
【讨论】:
以上是关于App Engine 调度程序何时使用新线程与新实例?的主要内容,如果未能解决你的问题,请参考以下文章
如果Flask应用程序在Google App Engine中不可用,如何提供默认错误页面
Google App Engine 上的错误 Python 2.7 - 无法使用 CGI 处理程序启用线程安全
如何将新服务部署到 Google App Engine 中的现有应用程序?