Perl's Parse::RecDescent поток безопасен?

У меня есть веб-приложение, которое использует парсер, созданный с помощью Parse::RecDescent. Объект синтаксического анализа необходим в нескольких частях приложения, и, поскольку анализатор занимает довольно много памяти, я до сих пор рассматривал объект синтаксического анализа как одиночный объект. Это хорошо работает в чистой среде CGI, так как только одно выражение анализируется одним и тем же объектом за один раз. Однако я не уверен, будет ли это работать при работе в среде, где один и тот же анализатор объектов анализирует более одной строки одновременно.

Например, если я попытаюсь запустить приложение под FastCGI, может ли это стать проблемой, если два запроса одновременно используют один и тот же объект синтаксического анализа для анализа разных строк?

Если мне нужно, я могу изменить приложение так, чтобы синтаксический анализатор больше не был синглтоном, однако я бы предпочел не делать этого, поскольку текущее решение проще.

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, и я бы сказал, что они даже будут использовать меньше памяти.

Другие вопросы по тегам