在Java Web应用程序中,通常会生成线程来处理Web请求。我指的是应用程序代码,而不是容器的线程来接受传入的客户端连接
在脚本语言中,例如Perl或Python,我的理解是最常使用多处理范例(fork进程)而不是多线程(fork线程)。
我个人发现分叉过程而不是Web服务器应用程序代码中的线程“怪异”而且更重
我对此是否正确?在这些框架中的Web处理期间是否正常分叉过程?
答案 0 :(得分:2)
Perl线程非常繁重(参见How do I reduce memory consumption when using many threads in Perl?)。从我读到的python中的线程受到全局解释器锁的阻碍。 Java中的线程似乎更轻量级,但不像Linux中的OS线程那样轻量级。
如果你想在Perl中进行繁重的网络连接你不使用线程,而是使用基于事件的编程,比如使用AnyEvent或POE,类似于具有Twisted框架的Python。有几个基于这些框架的Web服务器。 Java也有NIO框架,甚至在C现代快速Web服务器中,如nginx使用基于事件的编程而不是线程或进程。
我不知道任何常用的Web服务器,它会分叉处理请求。如果它们完全分叉,则使用预分叉模型,例如,他们预先分叉了许多工作进程(如果他们使用线程而不是进程,则为工作线程),如果有新请求进入,则由一个现有工作人员处理。这比fork-on-request模型要少得多,后者只有非常简单的服务器才能使用。具有基于事件的处理的服务器也可以分叉,但通常只能有效地使用多个CPU(例如,每个CPU一个进程)。
使用预分支Web服务器,Web应用程序通常根本不分叉,而只是使用当前进程。基于事件的Web服务器通常只在内部和快速处理静态内容,因为它们通过FCGI等接口连接到其他进程的速度较慢的动态内容,这些进程通常是预先分叉的。这节省了资源,因为对于普通网页,大多数请求都是针对静态内容的。
可能仍有理由在Web应用程序中进行分叉。这是,如果你需要在后台做一些工作(比如调整上传的图像大小),而页面已经完成,内容应该发送给用户。但即使在这种情况下,它也可以更好地扩展,以便有一个专门的进程/线程来完成这项工作,并且只为它提供任务。
关于创建线程与进程的性能:进程的分支在Unix / Linux(但不在Windows中)便宜,因为它简单克隆现有的进程结构并标记所有共享内存页(例如最初所有页面)作为写时复制。只有当新进程工作时,才会复制更改的内存页面(这是昂贵的部分)。创建线程的成本在编程语言和操作系统之间存在很大差异,并且不需要比分支新进程更快。