并发计算对Web开发很重要吗?

时间:2009-09-06 02:10:04

标签: python web-applications concurrency

假设我有一个在S服务器上运行的Web应用程序,每个服务器平均有C个核心。我的应用程序正在处理任何时刻的R请求的平均值。假设R大约是S * C的10倍,那么由于每个核心已经处理了大约10个请求,因此将多个核心的请求工作分散开来不会带来好处吗?

如果我是对的,为什么this guy说并发对Python作为Web开发语言的未来如此重要?

我可以看到为什么我的论点不正确的原因很多。也许应用程序会收到一些非常难以处理的请求,这些请求的数量超过可用内核。或者,请求的难度可能存在很大差异,因此一个核心可能不幸并且连续发出10个困难请求,结果是其中一些核心需要的时间比合理的长。鉴于撰写上述文章的人比我更有经验,我认为我错了很多,但我想知道原因。

5 个答案:

答案 0 :(得分:5)

在您设计的假设情况下,每个核心有大约10个“正在运行”的请求,只要明智地处理请求到核心的分配(可能即使是最简单的循环负载平衡也可以),它只是如果每个请求在其整个生命周期内存在于单个核心上,那就很好。

重点是,这种情况只有一种可能性 - 请求,这些请求在每个请求编组多个核心时真正受益(就低延迟而言)肯定是另一种可能性。我怀疑在今天的网络上你的场景更加普遍,但是它确实很好处理这两种类型,并且“批处理”后台处理也是如此....特别是因为核心数量(而不是每个核心的速度)这些日子里正在增加什么,并且会持续增长。

我很反对雅各布·卡普兰 - 莫斯的智慧,但我习惯于在我的雇主那里以比他似乎提倡的更好,更明确和更透明的方式获得相当好的并发性 - mapreduce for batch类似于作业,基于分布式哈希的分片,用于注册N个后端以分割1个查询的工作等。

也许我对Erlang,Scala或Haskell相对较新的软件事务内存没有足够的真实体验,看看它们如何能够扩展到数千个核心的数十个或几千个核心的高利用率低QPS,高Q工作量的工作负载...但在我看来,这种情况的灵丹妙药(扣除相对有限的情况子集,你可以转向mapreduce,pregel,分片等等)尚未以任何语言发明。使用明确的,精心设计的架构,至少在我的工作经验中,Python肯定不会比Java,C#或C ++更糟糕。

答案 1 :(得分:4)

我估计不会很快。大多数单个Web请求的生命周期都在一秒钟之内。鉴于此,分离Web请求任务本身而不是在Web核心上分发Web请求任务是没有意义的。某些Web服务器能够并且大多数已经完成。

答案 2 :(得分:1)

警告:我只是浏览了“并发”部分,这似乎就是你所指的。问题似乎是(当然这不是新的):

  • 由于GIL,Python线程不会并行运行。
  • 具有多个核心的系统将需要尽可能多的后端(实际上,您可能需要至少2xN个线程。)
  • 系统正朝着拥有更多内核的方向发展;典型的PC有四个核心,经济实惠的服务器系统有128个或更多核心可能并不遥远。
  • 运行256个单独的Python进程意味着不共享数据;整个应用程序和任何加载的数据都会在每个进程中复制,从而导致大量内存浪费。

最后一位是此逻辑失败的地方。实际上,如果你以天真的方式启动256个Python后端,那么就没有数据共享。但是,这没有预先考虑的设计:这是启动大量后端进程的错误的方式。

正确的方法是在单个主进程中加载​​整个应用程序(您依赖的所有Python模块等)。然后,该主进程会分离后端进程以处理请求。这些成为独立的进程,但标准的写时复制内存管理意味着已经加载的所有固定数据都与主服务器共享。主人事先加载的所有代码现在都在所有工作人员之间共享,尽管事实上他们都是独立的进程。

(当然,COW意味着如果你写它,它会创建一个新的数据副本 - 但加载后不应该改变编译的Python字节码之类的东西。)

我不知道是否存在与此相关的Python相关问题,但如果是这样,那些是要修复的实现细节。这种方法比试图消除GIL更容易实现。它还消除了传统锁定和线程问题的任何可能性。这些并没有它们在某些语言和其他用例中那么糟糕 - 线程之间几乎没有交互或锁定 - 但它们并没有完全消失,Python中的竞争条件也是跟踪的痛苦用任何其他语言来表达。

答案 3 :(得分:1)

您要忽略的一件事是,Web请求不是仅涉及CPU的一系列连续指令。

典型的Web请求处理程序可能需要对CPU进行一些计算,然后从磁盘读取一些配置数据,然后向数据库服务器询问必须通过以太网传输给它的一些记录,依此类推。 CPU使用率可能很低,但由于等待每一步之间的所有I / O,它仍然需要花费大量时间。

我认为,即使使用GIL,Python也可以在一个线程等待I / O时运行其他线程。 (其他进程肯定可以。)尽管如此,Python线程并不像Erlang线程:启动它们并且它会开始受到伤害。

另一个问题是记忆。 C库在进程之间共享,但(AFAIK)Python库不是。因此,启动10倍的Python进程可能会减少I / O等待,但现在每个核心加载的每个Python模块都有10个副本。

我不知道这些有多重要,但它们确实使事情复杂化,超出“R> 10 * S * C”。在Python世界中还有许多工作要做,以解决它们,因为这些问题并不容易。

答案 4 :(得分:0)

在文章中,他似乎将GIL列为阻止Python中Web应用程序并发处理的原因,我根本不明白。随着你变得越来越大,最终你将拥有另一台服务器,而GIL或者不是GIL,没关系 - 你有多台机器。

如果他说的是能够从一台计算机中挤出更多的东西,那么我认为这不是相关的,特别是对于大规模的分布式计算 - 不同的机器不共享GIL。而且,实际上,如果要在群集中安装大量计算机,最好有更多的中端服务器而不是单个超级服务器,原因很多。

如果他的意思是更好地支持功能和异步方法,那么我有点同意,但它似乎与他的“我们需要更好的并发”点相切。 Python现在可以拥有它(他承认),但显然,它不够好足够(所有因为GIL,自然而然)。老实说,看起来更像是对GIL的抨击,而不是对Web开发中并发性重要性的证明。

关于并发性和Web开发,关键是并发性是 hard 。 PHP之类的美妙之处在于 没有并发性。你有一个过程,你就陷入了这个过程。它简单易行。您不必担心任何类型的并发问题 - 突然编程很多更容易。