【发布时间】:2011-11-22 13:01:05
【问题描述】:
我正在用 Python 做一个简单的实验。我有一个“主”进程,负责所有其他进程,每个进程都通过 unix 套接字连接到主进程。我希望主进程能够监视所有套接字以获取响应-但理论上可能有近百个。线程将如何影响应用程序的内存和性能?最好的解决方案是什么?非常感谢!
【问题讨论】:
我正在用 Python 做一个简单的实验。我有一个“主”进程,负责所有其他进程,每个进程都通过 unix 套接字连接到主进程。我希望主进程能够监视所有套接字以获取响应-但理论上可能有近百个。线程将如何影响应用程序的内存和性能?最好的解决方案是什么?非常感谢!
【问题讨论】:
一百个并发线程可能正在推动线程的合理限制。如果您发现这是组织代码最简洁的方式,我会建议您试一试,但线程的扩展性确实不高。
更好的方法是使用select 之类的技术来等待其中一个套接字可读/可写/或报告错误。这种机制让您进入睡眠状态,直到发生有趣的事情,处理尽可能多的套接字有内容要处理,然后再次进入睡眠状态,所有这些都在一个执行线程中。删除多线程通常可以减少出错的机会,这种编程风格应该让您轻松进入数百个连接。 (如果你想超过 100 个,我会使用 poll 功能而不是 select - 不断重建有趣的文件描述符列表需要时间,poll 不需要。)
需要考虑的是Python Twisted Framework。他们已经竭尽全力提供一种一致的方法来将回调挂钩到这种精确类型的编程的事件上。 (如果你熟悉 node.js,它有点像,但 Python。)我必须承认对 Twisted 有一点反感——我从来没有在他们的文档中走得太远而不完全感到困惑——但是 a lot of people made it further in the docs than I did。你可能会发现它比我的更合适。
【讨论】:
poll 也适用于较少数量的套接字。我认为select 接口比poll 接口简单一点,但它们已经足够接近了。
epoll 绝对让在事件处理循环的任何给定迭代中在套接字上使用 部分读取 变得更加容易。 (select 和 poll 要求您记住您已经完成了部分读取——或者从不执行部分读取。)
对线程与进程进行套接字处理比较测试的最简单方法是使用 Python 标准库中的SocketServer。您可以通过继承 ThreadingMixIn 或 ForkingMixIn 轻松切换方法(同时保持其他所有内容相同)。这是一个simple example,可以帮助您入门。
另一种选择是select/poll approach 在单个进程和单个线程中使用非阻塞套接字。
如果您对已经完全开发和高度发展的软件感兴趣,请考虑这些基于 Python 的高性能服务器包:
【讨论】: