2014-09-04 4 views
2

У меня есть скрипт perl, который проверяет базу данных для внутренних запросов на вызов API.Каков наилучший способ подключения к нескольким URL-адресам одновременно с perl

Когда он видит один, он использует LWP для вызова API по запросу.

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

Сценарий относительно прост. Я кратко рассмотрел POE и AnyEvent, но не смог найти никаких учебников, которые помогут мне понять, как они будут использоваться в этом контексте. Похоже, что они предназначены в первую очередь для более сложных ситуаций.

Более упрощены, моя половинка-псевдо-код:

while (1) { 
    $url=getNextRequestFromDB(); 
    if ($url ne "") { 
     $request = new HTTP::Request('GET', $url); 
     my $response = $ua->request($request); 
     logResponse($response); 
    } 
    else { 
     sleep(5); 
    } 
} 

Я не возражаю, если ответ не зарегистрирован, или (предпочтительно), если он регистрируется отдельно.

ответ

2

LWP::Parallel Модуль CPAN соответствует требованиям, которые вы ищете. Он принимает список URL-адресов (поддерживает HTTP, ftp и URL-адреса файлов), подключает их параллельно, а затем ждет результатов.

+0

Это выглядит интересно, но я не уверен, что это поможет здесь. Например, если я получил 4 запроса в цикле 1 и запрос №1 занял 5 минут, то все равно за 5 минут до начала цикла 2, поэтому, если другой запрос был введен сразу после вызова кода в '$ pua-> wait', это все равно будет застревать до тех пор, пока не будут выполнены текущие 4 запроса. –

1

Чтобы распараллелить длительные операции в программах perl, используйте fork() или библиотеку потоков.

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

fork() возвращает вновь созданный идентификатор дочерних процессов, когда вы находитесь в копии программы PARENT и false, когда находитесь в дочернем.

# create 10 children 

my @children; 

for (my $count = 1; $count <= 10; $count++) { 
     my $pid = fork(); 
     if ($pid) { 
     # you are in the parent process 
     # print "child has $pid, parent $$\n"; 
     push(@children, $pid); 
     } elsif ($pid == 0) { 
        # You are in the child 
       while (1) { 
        ## Connect to the DB 
        ## fetch an api request 
        ## last if $no_request_left 
        ## run an api request 
       } 
       ## disconnect from DB 
       ## cleanup whatever needs to be done, then exit 
       exit 0; 
     } else { 
       die "couldnt fork: $!\n"; 
     } 



} 

foreach (@children) { 
     my $tmp = waitpid($_, 0); 
     print "pid $tmp found no more requests and exited\n"; 

} 

print "Main ends here\n"; 
+0

Если я правильно понимаю, у вас есть 10 вилок, каждый из которых выполняет весь мой процесс. Не удалось ли удалить db из вилки, чтобы каждый раз, когда он нашел запрос (вместо цикла for в вашем примере), он вилки, чтобы выполнить вызов API, а затем регистрирует ответ и завершает работу? Тогда нет необходимости в дополнительных подключениях к БД. –

+0

Это не сработает. Fork предоставляет дочерние процессы, которым требуется собственное соединение с БД. Если вам нужно разделить соединение с БД между дочерними элементами, вам нужно либо установить соединение в родительском, либо выполнить межпроцессное общение с родителем для всех запросов или использовать потоки. Разветвленное соединение БД обычно устаревает. – user4004936

+0

Приложение: вы можете переконфигурировать программу для этого рабочего процесса. Попросите родителя сделать все вещи БД, получить вызов api или достаточно короткий список/массив вызовов из БД, создать дочерний элемент, выбрать следующую команду, создать следующий дочерний элемент. Каждый ребенок обрабатывал свой список, а затем прерывался. – user4004936

0

Посмотрите на Mojo::UserAgent. У них есть примеры параллельных запросов внутри связанной документации.