6

我正在编写一个相当复杂的 Web 应用程序。Python 后端运行一种算法,其状态取决于存储在几个相互关联的数据库表中的数据,这些数据不经常更改,以及用户特定的数据经常更改。当用户使用应用程序时,算法的每个用户状态会发生许多小的变化。在每个用户的工作中经常使用该算法来做出某些重要的决定。

出于性能原因,对来自(半规范化)数据库数据的每个请求重新初始化状态很快变得不可行。例如,最好以某种方式缓存状态的 Python 对象,以便在必要时可以简单地使用和/或更新它。但是,由于这是一个 Web 应用程序,有多个进程为请求提供服务,因此使用全局变量是不可能的。

我已经尝试序列化相关对象(通过pickle)并将序列化数据保存到数据库,现在正在尝试通过memcached缓存序列化数据。但是,这仍然具有经常序列化和反序列化对象的巨大开销。

我查看了共享内存解决方案,但我发现唯一相关的是POSH。然而 POSH 似乎并没有被广泛使用,我觉得将这样一个实验性组件集成到我的应用程序中并不容易。

我需要一些建议!这是我开发 Web 应用程序的第一次尝试,所以我希望这是一个足够普遍的问题,以便有针对此类问题的众所周知的解决方案。在这一点上,假设 Python 后端在单个服务器上运行的解决方案就足够了,但是对于扩展到多个服务器的解决方案也可以加分:)

笔记:

  • 我有这个应用程序正在运行,目前正在使用并且有活跃用户。我一开始没有做任何过早的优化,然后根据需要进行优化。我已经完成了测量和测试,以确保上述问题是实际的瓶颈。我很确定我可以从当前设置中挤出更多性能,但我想问是否有更好的方法。
  • 设置本身仍在进行中;假设系统的架构可以是任何适合您的解决方案的架构。
4

6 回答 6

8

小心过早的优化。

补充:“Python 后端运行一个算法,其状态...”是 Web 框架中的会话。就是这样。让 Django 框架在缓存中维护会话状态。时期。

“当用户使用应用程序时,算法的每个用户状态会发生许多小的变化。” 大多数 Web 框架都提供缓存的会话对象。通常它是非常高性能的。请参阅 Django 的会话文档

建议。[修改]

看来你有一些有用的东西。利用杠杆来学习你的框架,学习工具,并了解你可以毫不费力地转动哪些旋钮。具体来说,使用会话状态。

其次,摆弄缓存、会话管理等容易调整的东西,看看你是否有足够的速度。通过尝试找出 MySQL 套接字或命名管道是否更快。这些是无编程优化。

第三,测量性能以找到您的实际瓶颈。准备好提供(并捍卫)测量值,使其足够细粒度,足以有用且足够稳定,以提供对备选方案的有意义的比较。

例如,显示持久会话和缓存会话之间的性能差异。

于 2008-12-01T11:29:48.337 回答
4

我认为多处理框架在这里可能适用 - 即共享 ctypes 模块。

多处理对 Python 来说是相当新的,所以它可能有一些奇怪的地方。我不太确定该解决方案是否适用于不是通过multiprocessing.

于 2008-12-01T11:32:43.523 回答
2

我认为你可以给 ZODB 一个机会。

“ZODB 的一个主要特性是透明性。您不需要编写任何代码来显式地从数据库读取对象或从数据库写入对象。您只需将持久对象放入一个像 Python 字典一样工作的容器中。里面的一切字典保存在数据库中。这个字典被称为数据库的“根”。它就像一个魔术袋;你放入其中的任何 Python 对象都会变得持久化。

最初它是 Zope 不可或缺的一部分,但最近也提供了一个独立的软件包。

它有以下限制:

“实际上,您可以在 ZODB 中存储的内容有一些限制。您可以将任何可以“腌制”的对象存储为标准的跨平台串行格式。可以腌制列表、字典和数字等对象。对象像文件、套接字和 Python 代码对象一样,不能存储在数据库中,因为它们不能被腌制。”

我已经阅读了它,但我自己还没有尝试过。

其他可能的事情可能是内存中的sqlite db,这可能会稍微加快进程 - 作为内存中的数据库,但您仍然必须做序列化的事情等等。注意:在内存中 db 的资源很昂贵。

这是一个链接:http ://www.zope.org/Documentation/Articles/ZODB1

于 2008-12-01T11:07:00.190 回答
2

首先,您的方法不是常见的 Web 开发实践。即使正在使用多线程,Web 应用程序也被设计为能够运行多处理环境,以实现可扩展性和更轻松的部署。

如果您只需要初始化一个大对象,并且以后不需要更改,您可以通过使用在创建 WSGI 应用程序时初始化的全局变量轻松完成,或者包含正在加载的对象的模块等,多处理对你来说很好。

如果您需要更改对象并从每个线程访问它,则需要确保您的对象是线程安全的,使用锁来确保这一点。并使用单个服务器上下文,一个进程。任何多线程 python 服务器都会很好地为您服务,FCGI 也是这种设计的不错选择。

但是,如果多个线程正在访问和更改您的对象,则锁定可能会对您的性能提升产生非常糟糕的影响,这可能会使所有好处都消失。

于 2008-12-01T13:47:51.537 回答
2

这就是 Durus,一个用于使用 Python 编程语言编写的应用程序的持久对象系统。Durus 提供了一种简单的方法来使用和维护一个或多个进程使用的对象实例的一致集合。持久实例的访问和更改通过缓存的 Connection 实例进行管理,该实例包括 commit() 和 abort() 方法,因此更改是事务性的。

http://www.mems-exchange.org/software/durus/

我以前在一些研究代码中使用过它,我想保留某些计算的结果。我最终改用pytables,因为它更好地满足了我的需求。

于 2009-05-17T02:31:06.547 回答
1

另一种选择是查看状态要求,听起来如果序列化是瓶颈,那么对象就非常大。你真的需要这么大的物体吗?

我知道在 Stackoverflow 播客 27 中,reddit 的人讨论了他们用于状态的内容,所以听听可能很有用。

于 2008-12-01T11:30:39.003 回答