【问题标题】:Is Perl's Parse::RecDescent thread safe?Perl 的 Parse::RecDescent 线程安全吗?
【发布时间】:2011-01-12 14:57:25
【问题描述】:

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

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

如果需要,我可以更改应用程序,使解析器不再是单例,但我不希望这样做,因为当前的解决方案更简单。

【问题讨论】:

  • FastCGI 真的在不同的线程中使用相同的解释器执行相同的 Perl 代码吗?我认为“快速”部分只是意味着服务器可以在对同一页面的单独调用中重用解释器。
  • 这对于 FastCGI 案例来说是一个非常有效的观点。我还没有在任何应用程序中使用过 FastCGI,所以我不能肯定。当我想到它时,似乎很有可能当时只有一个请求将由一个 Perl 解释器处理。如果是这样,我的潜在问题就会消失,我会很开心。

标签: perl parse-recdescent


【解决方案1】:

据我所知,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 解释器内部数据结构的副本(OP 树除外)。

这有效地为每个线程克隆一次$SingletonRD。没有保存内存。现在,如果您只在创建线程后设置解析器,变量将不会在它们之间共享,因此不会节省内存并且这里也没有线程不安全。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-15
    • 2016-02-29
    • 2018-07-18
    • 2011-07-04
    • 2014-04-26
    相关资源
    最近更新 更多