0

所以我的...错误...应用程序执行以下操作:

  • 在队列中收听“工作”
  • 每台服务器产生大约 100 个工作人员(跨约 3 个服务器),每个工作人员都在队列中侦听
  • 每个工作人员基本上都会做一些网络工作(ssh、snmp 等)(I/O 密集型),然后搅动输出(非常 cpu 密集型)

我已经完成了所有工作multiprocessing,而且效果很好。但是:每个工作人员使用的内存都比我想要的多(根据顶部,大约 30MB RES,450MB VIRT)。所以我有两个问题:

  • 我确定为什么开销如此之高的最佳方法是什么?我猜 COW 工作得不太好......我可以使用哪些模块在多处理之前获取所有主线程内存的快照,以便我可以尝试减少初始占用空间?

  • 鉴于我的大部分进程都是 cpu 绑定的,将我的代码移植到 gevent/twisted 会有好处吗?我想利用每台服务器的双六核。

谢谢!

4

2 回答 2

3

CPython 使用引用计数来实现所有 Python 对象的内存管理。其工作方式是将每个 Python 对象表示为一个结构,并且每个结构中都有一个字段,给出引用计数。每当对对象进行新引用时,该字段中的引用计数就会增加。每当放弃对该对象的引用时,该字段中的引用计数就会减少。一旦引用计数为零,解释器就可以确定不再需要 Python 对象,并且可以释放分配给表示它的结构的内存。

很多事情都会改变对象的引用计数。将它传递给函数或将其分配给(局部或全局)变量或对象的属性将增加引用计数(许多其他操作也会增加)。与此相反,引用计数会减少:例如,从函数返回会减少所有局部变量的引用计数。

与您的问题相关的所有原因是它应该让您了解为什么您摆脱的写时复制行为fork()不会帮助您节省大量内存。几乎立即,CPython 运行时将访问大部分内存页面(内存写入时复制的基本单位考虑 - 通常为 4kB,可能更大)并将大量 2 替换为 3 或将 4 替换为 3 或其他任何内容。这将强制复制进程的大部分内存。

事件驱动系统将通过让您同时执行许多 I/O 绑定任务来帮助解决此问题。您仍然可以使用多个进程(至少使用 Twisted)来利用您拥有的额外 CPU 资源。一个单一的、事件驱动的进程可以完成所有必要的联网,然后将生成的数据交给工作进程,这些工作进程可以使用其余的 CPU。不过,您可以更精确地确定在这些额外进程中运行的代码。根据您的问题,我怀疑您认为您的员工不需要加载到“主要”流程中的所有内容。使用 Twisted 的流程管理 API,他们不必在这些事情上花费任何内存。

于 2013-09-30T11:49:56.343 回答
1

Pycon 上有一个很棒的演讲,它解释了python 中内存使用的主题。这绝对是一个半小时的时间。

最重要的是,要真正了解使用了多少内存,您不应该查看最高输出,而是检查运行 100 个工作程序之前和之后有多少可用内存。

于 2013-09-30T14:06:56.140 回答