下面的代码在mod_cgi上运行良好,但在mod_perl上运行不好。代码只是在创建第一个线程时崩溃。关于如何在mod_perl上实现线程,有什么想法吗?真的有可能吗?我错过了什么?
use strict;
use warnings;
use threads;
print "Content-type: text/htmlnn";
sub testthread{
my $value = shift;
print "<br>test - $value"
}
my @threads = ();
push(@threads, threads->new(&testthread, 1));
push(@threads, threads->new(&testthread, 2));
foreach (@threads) {
$_->join;
}
exit;
没有给出错误消息。我的网页/脚本刚刚停止,并将此错误发送给浏览器:www.abcd.com页面不工作www.abcd.com未发送任何数据。奇怪的是,如果我通过命令行执行脚本,它会正常工作。
那么线程真的不能使用mod_perl吗?
我还没有研究线程是否可以使用mod_perl2
。请记住,mod_perl
的目的是在Apache进程中运行一组持久的Perl解释器。
还要记住,Apache可以杀死那些需要很长时间才能响应的CGI脚本。现在,在这个组合中添加一组线程,这些线程是您的CGI脚本在Apache中的某个持久Perl进程中管理的,可以随时终止;好主意"我从来不会想到这是我在CGI编程中遇到的任何问题的解决方案。
你可能会做什么,也可能不会做什么,这在很大程度上取决于你选择的MPM,以及你使用的httpd
和perl
是如何编译的,等等。
你需要解释为什么你认为你需要线程。你试图解决的问题是什么?在mod_perl
下运行的CGI脚本中使用线程将如何帮助你解决这个问题?
请参阅mod_perl文档:
线程支持
为了适应Apache 2.0线程体系结构(用于线程MPM),mod_perl 2.0需要使用线程安全的perl解释器,也称为"perl解释器";CCD_ 6";(解释器线程)。这种机制可以在编译时启用,并确保每个Perl解释器使用其专用
PerlInterpreter
结构来存储其符号表、堆栈和其他Perl运行时机制。当采用这种分离时,同一进程中的任何数量的线程都可以安全地执行对Perl的并发回调。当然,这需要每个线程都有自己的PerlInterpreter
对象,或者至少每个实例在任何给定时间都只能由一个线程访问。第一代
mod_perl
只有一个PerlInterpreter,它由父进程构造,然后跨分支继承到子进程。mod_perl
2.0具有可配置数量的PerlInterpreter
和两类解释器,即父解释器和克隆解释器。父级类似于mod_perl
1.0中的父级,其中在启动时创建的主解释器编译任何预加载的Perl代码。使用Perl API Perl_clone()函数从父项创建克隆。在请求时,父解释器只用于制作更多的克隆,因为克隆是实际处理请求的解释器。Perl注意只复制可变数据,这意味着不需要运行时锁定,并且从父级共享语法树等只读数据,这将减少mod_perl
的总体内存占用。mod_perl不是默认为每个线程创建一个
PerlInterpreter
,而是创建一个解释器池。池机制有助于大大减少内存使用。如前所述,语法树在所有克隆的解释器之间共享。如果您的服务器提供的mod_perl
请求多于,则PerlInterpreter
的数量少于线程数量将明显减少内存使用。最后,也许也是最大的胜利是内存重用:当对Perl子例程进行调用时,在第一次使用变量时会为其分配内存。变量的后续使用可能会分配更多的内存,例如,如果标量变量需要保存比以前更长的字符串,或者数组添加了新元素。作为一种优化,Perl保留这些分配,即使它们的值为"0";超出范围";。mod_perl 2.0可以更好地控制哪些CCD_ 17用于传入请求。口译员存储在两个链表中,一个用于可用口译员,另一个用于繁忙口译员。当需要处理一个请求时,从可用列表的头部提取一个解释器,并在完成后放回同一列表的头部。这意味着,例如,如果您有10个解释器被配置为在启动时克隆,但同时使用的解释器不超过5个,那么这5个解释器将继续重用Perl的分配,而其他5个解释器仍然小得多,但如果需要,可以随时使用。池的各种属性可以使用特定于线程模式的指令进行配置。
解释程序池机制已经被抽象为被称为"API"的API;tipool";,线程项目池。此池可用于管理任何数据结构,在这些数据结构中,您希望拥有的线程数小于配置的线程数。例如,基于tipool的
Apache::DBI
的替换将允许重用同一进程的多个线程之间的数据库连接。线程环境问题
虽然
mod_perl
本身是线程安全的,但您的代码的线程安全性可能存在问题。有关更多信息,请参阅mod_perl下的线程编码问题。另一个问题是;全局";变量仅对创建变量的解释器是全局的。可以在同一进程中运行的多个线程之间共享变量。有关更多信息,请参阅:共享变量。
我们使用Apache事件多处理模块(MPM)和Apache::DBI与MySQL 5.7运行mod_perl,以处理大量用户登录和开始测验/考试。
我们将Apache 2.4配置为从50个子线程开始,每个子线程运行100个线程,总共有5000个线程可用于请求。因为mod_perl也运行多线程,并且绑定到Apache中(在启动时),所以与其他语言相比,内存消耗最小。
我们将Apache设置为始终有3500个可用线程,并且最多有200个子线程(20000个线程)。儿童在处理10000个请求后进行回收(以防内存泄漏)。当Apache每天晚上回收日志时,Apache会重新启动mod_perl和所有数据库连接,并重新启动5000个可用线程。
有了mod_perl,我们从50个孩子开始匹配apache的孩子,它还回收了它的孩子。
在虚拟服务器指令中,我们有:
PerlInterpStart 50PerlInterpMaxSpares 50PerlInterpMax 100
真正的简单性提供了非常高的可扩展性和稳定性以及低成本的硬件。而且它在窗户上也运行良好。如果你的东西不是多线程运行的,那么它只限于每个请求需要一个子线程(1:1的比例),而不是一个线程(1:100的比例)。每个孩子都需要一个程序实例来运行(Java除外),因此与使用mod_perl相比,内存消耗非常高。我们知道人们说它很旧,但它运行得很好,很稳定,在可能比任何其他语言都多的操作系统上得到支持,而且它确实有效。