And*_*lke 16 locking multiprocessing preforking
我正在研究一些以Apache的MPM prefork服务器为模型的Python代码.我是一名应用程序员而不是网络程序员,自从我读Stevens已经10年了,所以我正努力加快理解代码.
我找到了Sander Temme对Apache的prefork代码如何工作的简短描述.
父进程通常以root身份运行,绑定到套接字(通常是端口80或443).它生成子进程,继承了套接字的打开文件描述符,并将uid和gid更改为非特权用户和组.子节点构造一个侦听器文件描述符的轮询集(如果有多个侦听器)并监视它/它们上的活动.如果找到活动,则子活动在活动套接字上调用accept()并处理连接.完成后,它返回观察pollset(或监听器文件描述符).
由于多个子节点处于活动状态并且它们都继承了相同的套接字文件描述符,因此它们将观察相同的轮询集.接受互斥锁只允许一个孩子实际观察轮询集,一旦找到一个活动套接字,它将解锁互斥锁,以便下一个孩子可以开始观看轮询集.如果只有一个侦听器,则不使用接受互斥锁,并且所有子节点都将挂起在accept()中.
这几乎就是我正在寻找的代码的工作方式,但我不了解一些事情.
1)"孩子"和"听众"之间有什么区别?我认为每个孩子都是一个倾听者,这对我正在看的代码都是如此,但在Temme的描述中,可以有"单个听众"和"孩子".孩子什么时候会有多个听众?
2)(与1相关)这是一个进程互斥锁还是系统互斥锁?就此而言,为什么要使用互斥锁?不接受(2)在所有听众中做自己的互斥量?我的研究表明我确实需要一个互斥锁,并且互斥锁必须跨越整个系统.(羊群,信号量等)
特梅继续说:
儿童在上次提出请求时记录在共享内存区域(记分板)中.空进程可能会被父进程杀死以满足MaxSpareServers.如果太少的孩子闲置,父母将产生孩子以满足MinSpareServers.
3)这个实现是否有一个很好的参考代码(最好是在Python中)?我找到了Perl的Net :: Server :: Prefork,它为记分板使用管道而不是共享内存.我发现了一篇文章兰德尔·施瓦茨只做了preforking但没有做的记分牌.
来自Perl Cookbook的pre-fork示例没有任何关于select的锁定,Chris Siebenmann的Python示例说它基于Apache但是使用成对的套接字用于记分板,而不是共享内存,并使用套接字进行控制,包括控制给定的孩子'a'ccept.这根本不符合Apache描述.
Gra*_*ton 16
关于(1),监听器仅仅是对存在接受连接的套接字的引用.由于Apache可以同时接受多个套接字上的连接,例如80/443,因此有多个侦听器套接字.当它到来时,每个子进程都需要监听所有这些套接字.由于accept()一次只能在一个套接字上完成,因此它之前是poll/select,因此知道应该在哪个监听器套接字上执行accept.
关于(2),它是全局或跨进程的互斥体.也就是说,锁定它的一个进程将阻止尝试获取相同锁的其他进程.尽管accept()在技术上会将进程序列化,但是多个侦听器套接字的存在意味着你不能依赖它,因为你事先不知道哪个套接字要执行接受.即使在单个侦听器套接字的情况下,接受互斥的原因是如果有大量进程处理请求,那么如果操作系统唤醒所有进程以查看哪个进程有accept()返回它,则可能相当昂贵.由于Apache在prefork模式下可能有100多个进程,这可能会导致问题.
因此,如果您只有一个侦听器套接字并且知道只有少数进程想要执行accept()调用,那么您可以取消跨进程接受互斥锁.