Perl的Parse :: RecDescent线程安全吗?

时间:2010-02-03 13:24:01

标签: perl parse-recdescent

我有一个使用Parse :: RecDescent创建的解析器的Web应用程序。应用程序的几个部分需要一个解析器对象,因为解析器占用了相当多的内存,所以我现在将解析器对象视为单例。这在纯CGI环境中运行良好,因为同一对象一次只能解析一个表达式。但是,我不确定当在同一个对象解析器当时正在解析多个字符串的环境中运行时,这是否仍然有用。

例如,如果我尝试在FastCGI下运行应用程序,如果两个请求同时使用相同的解析器对象解析为不同的字符串,它会成为问题吗?

如果我需要,我可以更改应用程序,以便解析器不再是单例,但我不喜欢,因为当前的解决方案更简单。

1 个答案:

答案 0 :(得分:4)

据我所知,FastCGI不使用Perl线程,而是使用进程。因此,你应该是安全的。

此外,如果您使用Perl线程和Parse :: RecDescent,您可能从不使用同一个对象同时解析不同的东西。伪代码:

use threads;
use Parse::RecDescent;
our $SingletonRD = Parse::RecDescent->new($grammar);

my @threads = map {threads->new(\&thread_loop)} (1..5);

sub thread_loop {
    $SingletonRD->parse($text);
}

这是在单例之后创建线程的示例。这是发生的事情:

  • 您创建单例对象并将其存储在$SingletonRD
  • 您创建(循环)五个线程。当产生一个新线程时,perl会这样做
    • 创建全局符号表的副本。这包括所有包变量和子例程。
    • 创建各种perl-interpreter内部数据结构的副本(OP树除外)。

这有效地为每个线程克隆$SingletonRD一次。没有记忆。现在,如果你只是在创建线程之后才设置解析器,那么开始时就不会在它们之间共享变量,因此没有内存在这里保存没有线程不安全。

原则上,您可以使用threads :: shared在线程之间共享数据。但这并不(容易)处理对象和复杂的嵌套结构。因此,对于Parse :: RecDescent解析器来说,这可能是不可能的。

PS:看看Parse :: Yapp还是更好,Parse :: Eyapp。它们比Parse :: RecDescent快得多(算法上),我直觉地说它们甚至可能使用更少的内存。