Как использовать коллекцию arangodb в многопроцессорном режиме

Я использую Anyevent :: Fork :: Pool или Parallel :: ForkManager для создания 100 perl-процессов. Я хотел бы создать базу данных и коллекцию в Global и использовать объект коллекции в функции. Но это не работает. Мой пример кода следующий:

use ArangoDB;
my $itdb = ArangoDB->new(
{
    host       => '10.211.55.18',
    port       => 8529,
    keep_alive => 1,
    timeout    => 10,
}
);
my $Node_Coll = $itdb->( 'Node' );

...

sub function{
    $Node_Coll->count();
}

Это обратная связь «Ошибка не может вызвать метод http_get для неопределенного значения». Я печатаю $ Node_Coll в global и function. Это другое.

В глобальном режиме $ Node_Coll является нормальным. Но это неправильно по функциям. В функции: bless ({'db' => undef, 'name' => 'Node', 'status' => 3, 'code' => 200, '_api_path' => '/ _api / collection / 250177068120', 'id' => '250177068120', 'connection' => undef}, 'ArangoDB :: Collection');

Если я поставлю «my $ Node_Coll = $ itdb -> ('Node');» в локальной функции все нормально. Именно так. подфункция {my $ Node_Coll = $ itdb -> ('Узел'); $ Node_Coll-> count (); }

Не знаю, почему это так работает. Я думаю, что можно использовать один сокет в многопроцессорном режиме, когда "$ itdb -> ('Node');" в глобальном. Потому что "$ itdb -> ('Node');" отправит запрос http_get, это вызовет дополнительную нагрузку, особенно в среде с несколькими процессами. Лучше, если мы сможем его спасти.

ОБНОВЛЕНИЕ ОТ 10.08.2014: Подготовка данных: Вставьте некоторые данные в сборник «Узел». Метод выполнения: 1. Сохранить сценарий. И выполните $. / Count_srv.pl 2. изменили скрипт. Комментарий "my $ Node_Coll = $ itdb -> ('Node');" в count (). Раскомментируйте в global. И выполните $. / Count_srv.pl

count.pm следующий:

package Count;
use ArangoDB;

my $itdb = ArangoDB->new(
{
    host       => '10.211.55.18',
    port       => 8529,
    keep_alive => 1,
    timeout    => 10,
}
);
#my $Node_Coll = $itdb->( 'Node' );

sub count{
    my $Node_Coll = $itdb->( 'Node' );
    my $count = $Node_Coll->count();
    print "The count is ", $count, "\n";
}

count_srv.pl следующий:

use Parallel::ForkManager;
use count;

my $process_num = 10;
$pm = Parallel::ForkManager->new($process_num);

for(1..$process_num){
# Forks and returns the pid for the child:
my $pid = $pm->start and next;

Count::count();

$pm->finish; # Terminates the child process
}
$pm->wait_all_children;

person Hansen    schedule 07.10.2014    source источник
comment
Не могли бы вы разместить здесь пример клиентской программы (с Pool или с ForkManager) как с рабочим, так и с нерабочим вариантами? Иначе сказать сложно. Спасибо!   -  person stj    schedule 08.10.2014
comment
Спасибо за ваш ответ! Я приложил свой пример программы. Разница в том, что мой $ Node_Coll = $ itdb - ›('Узел'); в глобальном или в count ().   -  person Hansen    schedule 08.10.2014
comment
Мне кажется, что использование одного и того же соединения в нескольких параллельных потоках не работает, поскольку клиентские потоки будут отправлять свои данные по одному и тому же соединению параллельно, чередуя свои записи и чтения. Результат будет недетерминированным и, вероятно, искаженным. Я думаю, что было бы намного лучше создать одно соединение для каждого разветвленного потока, которое гарантированно будет использоваться только одним потоком. Я думаю, что это разумно, и накладные расходы на установление нескольких подключений должны быть незначительными, поскольку каждый рабочий, вероятно, в любом случае отправляет много последующих запросов.   -  person stj    schedule 08.10.2014
comment
Моя продуктовая программа основана на событии. Если он получил событие, Count :: count () будет выполнен один раз. Поэтому я не люблю ставить $ itdb - ›('Узел'); в count (), это дополнительная нагрузка на выполнение каждого события. Поэтому я думаю, что сложно реализовать создание одного соединения для каждого разветвленного потока, и одновременное установление нескольких соединений должно быть незначительным.   -  person Hansen    schedule 08.10.2014
comment
Понял. Но несколько потоков, записывающих данные в одно и то же общее соединение, также, вероятно, не будут работать. Например, если один поток пишет в соединение и ожидает ответа, вы не можете быть уверены, что другой из ваших потоков сначала украдет ответ из соединения. Думаю, вам понадобится несколько подключений. Может быть, можно создать пул потоков с одним подключением для каждого и разбудить его при возникновении события?   -  person stj    schedule 08.10.2014
comment
Спасибо! Я пробовал использовать Anyevent :: Fork :: Pool для этого. Ничего страшного. Он предоставляет параметр init = ›insert :: init,. Я поместил ArangoDB- ›new и $ itdb-› ('Node') в init (), init () выполняется только один раз, а count () будет выполняться много раз. Кажется, сейчас все идеально.   -  person Hansen    schedule 09.10.2014


Ответы (1)


Чтобы это работало с несколькими процессами, вам также потребуется несколько подключений (в идеале по одному на процесс). В противном случае единое (общее) соединение будет использоваться параллельно несколькими процессами, и это может испортить его.

Можно заранее создать пул соединений и передать простаивающее соединение из пула дочернему процессу при его разветвлении. Когда дочерний процесс завершится, вы можете вернуть соединения в пул. Понятия не имею, как это работает с Perl, просто хотел поделиться общей идеей.

person stj    schedule 21.10.2014