如何在内存使用量大的 Perl 守护程序中处理多个套接字?

Posted

技术标签:

【中文标题】如何在内存使用量大的 Perl 守护程序中处理多个套接字?【英文标题】:How can I handle multiple sockets within a Perl daemon with large memory usage? 【发布时间】:2010-09-26 10:09:42 【问题描述】:

我已经使用 IO::Socket::INET 使用 Perl 创建了一个客户端-服务器程序。我通过基于 CGI 的站点访问服务器。我的服务器程序将作为守护程序运行并接受多个同时连接。我的服务器进程消耗大约 100MB 的内存空间(9 个大型阵列,许多阵列......)。我希望这些哈希值驻留在内存中并共享它们,这样我就不必为每个连接都创建它们。哈希创建需要 10-15 秒。

每当通过套接字接受新连接时,我都会派生一个新进程来处理接收到的每个连接。由于父进程很大,每次 fork 时,处理器都会尝试为新子进程分配内存,但由于内存有限,生成新子进程需要大量时间,从而增加了响应时间。很多时候,即使是单个连接,它也会挂起。

父进程创建 9 个大哈希。对于每个孩子,我需要以只读模式引用一个或多个哈希。我不会通过孩子更新哈希值。我想使用写时复制之类的东西,通过它我可以与所有孩子共享由父母创建的整个 100mb 或整个全局变量?或任何其他机制,如线程。我希望服务器每秒至少会收到 100 个请求,并且它应该能够并行处理所有这些请求。平均而言,一个孩子会在 2 秒内退出。

我在只有 1GB RAM 的 Windows XP 上使用 Cygwin。我没有找到任何方法来克服这个问题。你能提出一些建议吗?如何共享变量并每秒创建 100 个子进程并对其进行管理和同步,

谢谢。

【问题讨论】:

【参考方案1】:

除了分叉之外,还有另外两种处理并发连接的方法。要么使用线程,要么使用轮询方法。

在线程方法中,每个连接都会创建一个新线程来处理套接字的 I/O。线程在创建进程的同一虚拟内存中运行,并且可以访问其所有数据。确保正确使用锁来同步对数据的写访问。

更有效的方法是通过 select() 使用轮询。在这种情况下,单个进程/线程处理所有套接字。这是在大多数工作将是 I/O 并且花费在等待 I/O 请求完成上的时间用于处理其他套接字的假设下工作的。

进一步研究这两个选项,然后决定哪一个最适合您。

例如:http://www.perlfect.com/articles/select.shtml

【讨论】:

【参考方案2】:

如果您有这么多数据,我想知道您为什么不简单地使用数据库?

【讨论】:

【参考方案3】:

这种架构不适合 Cygwin。在真正的 unix 系统上分叉很便宜,但在像 Cygwin 这样的假 unix 系统上则非常昂贵,因为必须复制所有数据(真正的 unice 使用写时复制)。使用线程会改变内存使用模式(更高的基本使用率,但每个线程的增加量较小),但它仍然可能效率低下。

我建议您使用单进程方法,使用轮询,也可以使用非阻塞 IO。

【讨论】:

Perl 的 fork 的模拟 Windows 版本不是同一个进程中的线程吗?这让我最近有点吃惊,这就是我记得读过的内容。 是的,它们都是作为 Win32 线程实现的,但是从 Perl 的角度来看,假进程的实现方式与 ithread 不同。

以上是关于如何在内存使用量大的 Perl 守护程序中处理多个套接字?的主要内容,如果未能解决你的问题,请参考以下文章

我可以在 OS X 10.5 上使用 dtrace 来确定我的哪个 perl 子程序导致的内存分配最多吗?

如何使用 Perl 处理大数据文件?

如何在 linux 中将 Perl 脚本作为系统守护进程运行?

如何在长时间运行的 Perl 程序中找到内存泄漏?

PHP如何实现daemon守护进程和master-woker模式进程

使用完成处理程序进行异步调用的多个 URLSession dataTask 导致内存上升