<rmcreative>

RSS

rolling-curl

13 мая 2010

rolling-curl — PHP-класс для параллельного выполнения большого количества асинхронных HTTP-запросов при помощи curl, написанная Josh Fraser и поддерживаемая на данный момент мной.

Правильно чистит память, не простаивает зря, выполняя одновременно заданное число запросов. Обрабатывает каждый ответ сразу после выполнения запроса.

Пример:

// URL, которые будем обрабатывать
$urls = array(
  "http://www.google.com",
  "http://www.facebook.com",
  "http://www.yahoo.com",
);
 
// функция для обработки ответа
function request_callback($response, $info) {
  // получаем title страницы
  if (preg_match("~<title>(.*?)</title>~i", $response, $out)) {
    $title = $out[1];
  }
  echo "<b>$title</b><br />";
  print_r($info);
  echo "<hr>";
}
 
$rc = new RollingCurl("request_callback");
// одновременно позволим не более 20 запросов
$rc->window_size = 20;
foreach ($urls as $url) {
    // добавляем запросы в очередь
    $request = new RollingCurlRequest($url);
    $rc->add($request);
}
// запускаем
$rc->execute();

Пользуемся

Комментарии RSS

  1. №2528
    mktums
    mktums 13.05.2010, 14:41:17

    Спасибо :) Возьму на заметку :)

  2. №2529
    Ewg
    Ewg 13.05.2010, 14:43:13

    Как скачать?

  3. №2530
    Максим
    Максим 13.05.2010, 17:38:24

    Удобная вешь+ еще и на curl. А по асинхроным серверам на php ничего не завалялось случайно ?

  4. №2531
    Andron
    Andron 13.05.2010, 17:56:25

    Спасибо, возможно пригодится :)

  5. №2532
    Sam
    Sam 13.05.2010, 18:53:30

    Ewg

    Можно забрать из SVN Google Code.

  6. №2533
    Sam
    Sam 13.05.2010, 19:10:35

    Максим

    У меня лично по асинхронным нет, но есть http://github.com/kakserpom/phpdaemon.

  7. №2534
    Сергей
    Сергей 13.05.2010, 23:16:25

    Зачем

    $request = new Request($url);

    если можно

    $rc->request($url);

    Вообще довольно странная библиотека...

  8. №2535
    Сергей
    Сергей 14.05.2010, 0:07:54

    И правда что-то не так

    Почему то при запуске example.php функции curl_multi_exec и curl_multi_info_read у меня запускались по 94000 с лишним раз.

    Что то там явно не так. Будто цикл какой-то крутится без таймаутов.

    Там вот эта последовательность

      160,3418     527568         -> curl_multi_exec() /home/seriy/rolling-curl-read-only/RollingCurl.php:255
      160,3418     527568         -> curl_multi_info_read() /home/seriy/rolling-curl-read-only/RollingCurl.php:259
      160,3419     527568         -> curl_multi_exec() /home/seriy/rolling-curl-read-only/RollingCurl.php:255
      160,3419     527568         -> curl_multi_info_read() /home/seriy/rolling-curl-read-only/RollingCurl.php:259
      160,3419     527568         -> curl_multi_exec() /home/seriy/rolling-curl-read-only/RollingCurl.php:255
      160,3420     527568         -> curl_multi_info_read() /home/seriy/rolling-curl-read-only/RollingCurl.php:259
      160,3420     527568         -> curl_multi_exec() /home/seriy/rolling-curl-read-only/RollingCurl.php:255
    

    Очень много раз повторяется (по 20-100 тыс раз)

    Я бы не советовал этот класс использовать..

  9. №2536
    Сергей
    Сергей 14.05.2010, 1:01:31

    Да и ничуть оно ни асинхронное/неблокирующее.

    Если в example.php в самом конце после $rc->execute(); вставить например print "Hello world"; то если все действительно асинхронно, то сперва напечатается "Hello world" а потом уже все остальное а тут сперва отрабатывает полностью $rc->execute(); (т.е. оно заблокировало все операции) и только потом print

    Так что асинхронностью тут и не пахнет. Многопоточность разве что...

  10. №2537
    Psih
    Psih 14.05.2010, 1:40:05

    http://github.com/kakserpom/phpdaemon - ыыы, Данко! Я этого психа знаю лично - он на демонах на PHP собаку съел, целую стаю, стаж у него с этим лет 6-7 точно. Так что это реально хорошее решение будет, от опытного спеца :)

  11. №2538
    Sam
    Sam 14.05.2010, 3:02:47

    Сергей

    Слово «асинхронные» тут относится именно к запросам и их обработке, а не к библиотеке в целом.

    Советую почитать про curl_multi_exec и curl_multi_info_read.

  12. №2543
    Сергей
    Сергей 14.05.2010, 22:44:17

    Sam

    Ок, насчет асинхронности в целом согласен, хотя к библиотеке в целом это не очень подходит.

    Но то, что там в какой-то момент начинает крутиться цикл по 20-90 тыс итераций это явно проблема.

  13. №2545
    Sam
    Sam 15.05.2010, 0:40:20

    Сергей

    Для curl_multi это совершенно нормально и указано в описаниях к методам.

  14. №2547
    Константин
    Константин 15.05.2010, 1:25:26

    Спасибо, но не пойму вот чего – я хочу сделать 5 миллионов запросов в 5 потоков. Все 5 миллионов я в $requests, понятное дело, не засуну – память не резиновая. Хотелось бы добавлять запросы в коллбэке по мере их выполнения. Однако приходится дождаться выполнения всех 5 запросов в первом потоке, и затем запускать следующий поток.

    Либо делать множество более коротких очередей – скажем, 5 тысяч раз по 1000 урлов. Что уже лучше, но усложняет логику. Есть выход?

  15. №2553
    Sam
    Sam 16.05.2010, 13:49:21

    В самой библиотеке выхода, думаю, нет. Занесите в тикет, надо будет подумать.

  16. №2609
    alexf2000
    alexf2000 02.06.2010, 17:01:48

    Может ли один из урлов завесить выполнение всех запросов? Если скажем в списке урлов не яхо, а вася.пупкин.цюрюпинск.херсон.уа и на этом сервере днс сначала 3 минуты думает, а потом не отвечает и до хттп соотсветственно дело даже не доходит или доходит, но сервер выдаёт мегабайтный файл по 1 байту в секунду? :)

  17. №2613
    Sam
    Sam 03.06.2010, 12:27:17

    Нет, не может.

  18. №2661
    Jei
    Jei 29.06.2010, 17:16:23

    Возникла пара вопросов:

    1) при работе скрипта (параллельно логинишься на два сайта; после этого параллельно забирается контент одной нужной страницы с каждого сайта) процес апача грузит проц на 50%. Это нормально или проблема конкретно у меня? ОС - виндовсХР, пакет - денвер+расширения, $rc->execute() - чтобы залогиниться и куки получить, второй $rc->execute()- чтобы получить контент.

    2) Хотелось бы, чтобы после того как залогинишься на сайте, сразу начинал работать другой запрос для получения контента страницы, и после получения парситься, независимо от запросов к другим сайтам. Такое возможно с данным функционалом?

  19. №2935
    Turbonist
    Turbonist 27.08.2010, 0:40:17

    Привет!

    Спасибо за либу. Очень пригодилось.

    Есть вопрос.

    С учетом того, что:

    запросов допустим 1000, а

    $rc->window_size = 20;
    for($i=0;$i<1000;$i++){
    $request = new Request($url . $i);
    $request->options = array(CURLOPT_TIMEOUT => 3);
    $rc->add($request);
    }

    , то либа должна отрабатывать каждые 3 сек минимум 20 запросов. Независимо от скорости получения контента (ибо CURLOPT_TIMEOUT => 3). Значит на всю операцию должно уйти не более 150 сек. Добавим 150 сек для прочих операций. Итого 5 мин. Однако, на деле может и час и два работать. Такое впечатление, что после первых 20 потоков переходит в режим однопоточности + не работает CURLOPT_TIMEOUT.

    С чем может быть связано?

  20. №2937
    Turbonist
    Turbonist 27.08.2010, 2:34:21

    в догонку к предыдущему посту

    [total_time] => 35.851
        [namelookup_time] => 0.06
        [connect_time] => 18.847
        [pretransfer_time] => 18.847
        [starttransfer_time] => 35.781

    как-то эти цифры не совместимы с

    $rc->options = array(CURLOPT_TIMEOUT => 5,CURLOPT_CONNECTTIMEOUT => 5);

    версия curl libcurl/7.19.6

    может дело в самой либе curl?

  21. №2910
    Sam
    Sam 27.08.2010, 13:02:45

    Jei

    1) Не уверен. У меня не наблюдается.

    2) Да, в коллбэках писать надо.

    Turbonist

    Скорее всего в curl. Параметры либе вроде передаются.

  22. №2943
    Turbonist
    Turbonist 27.08.2010, 16:58:37

    Скорее всего в curl. Параметры либе вроде передаются.

    на кодах в вопросах, 12 вопрос, чел тоже испытывает проблемы с тем же самым.

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

  23. №3272
    Андрей
    Андрей 22.10.2010, 22:23:48

    Пробую использовать в библиотеке список (массив) проксей - если урл не сработал с текущей проксей, необходимо заново поставить этот урл в очередь "скачиваний" со следующей по порядку проксей.

    Создавать еще один новый объект RollingCurl и запускать еще один execute не хочется, т.к., вероятно, одновременных процессов уже будет не window_size, а больше.

    Если делать $rc->add($request), то как лучше его перезапустить с учетом того, что часть запросов уже была отработана и второй раз делать их же нелогично? Сразу же заново запускать $rc->execute()? Или $rc->add($request) добавит урл с новой проксей в существующую очередь? Может ли получится так, что execute полностью выполнится до того, как будет добавлена урл с новой проксей и как это избежать?

    P.S. Проверку, сработала ли прокси, пока планирую делать в функции request_callback примерно таким образом: if ($info['http_code']==501|502|503|504|505) {...}

  24. №3328
    Андрей
    Андрей 01.11.2010, 9:33:55

    Еще один вопрос...

    Подскажите, пожалуйста, как настроить паузу между отправкой запросов на удаленный сервер, чтобы распределить его нагрузку во времени, т.е. чтобы между запусками отдельных curl было не менее nn секунд.

  25. №3331
    Sam
    Sam 01.11.2010, 12:35:47

    С очередями пока есть определённые проблемы. И вроде как есть решение. Надо будет его обкатать.

    Пауз между запросами пока не предусмотрено. Нагрузку можно уменьшить выставив размер окна в единичку.

  26. №3338
    Андрей
    Андрей 02.11.2010, 12:57:17

    Судя по обсуждениям в форумам curl_multi_exec, возможно, это можно сделать добавлением usleep в RollingCurl.php примерно так:

        do {
            while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM) usleep(4000000); //делаем паузы 4 сек между запросами
            if ($execrun != CURLM_OK)
                break;
            // a request was just completed -- find out which one
            while ($done = curl_multi_info_read($master)) {
    
    

    Если гипотеза подтвердиться, пожалуйста, проапдейте RollingCurl.php.

  27. №3339
    Sam
    Sam 02.11.2010, 13:27:05

    Есть подозрение, что usleep() затормозит все потоки.

  28. №3355
    Stargazer
    Stargazer 09.11.2010, 0:13:57

    Sam, а можно ли сделать так, чтобы каждый запрос через свою проксю ходил?

  29. №3356
    Sam
    Sam 09.11.2010, 12:53:22

    Можно. См. RollingCurlGroup.

  30. №3794
    Владимир
    Владимир 26.01.2011, 0:36:26

    Здравствуйте! У меня приведенный пример не работает, выводится ошибка Fatal error: Class 'Request' not found in P:\home\localhost\www\multicurl\testRollingCurl.php on line 114 а если я вместо строки $request = new Request($url); пишу строку $rc->request($url); то скрипт работает неправильно. у меня в массиве порядка 90 адресов url, в настройках я указываю $rc->window_size = 10; скрипт выводит всего 6 результатов. Подскажите пожалуйста, где искать ошибку, т.к. я только учусь.

  31. №3795
    Sam
    Sam 26.01.2011, 4:15:44

    Request в новых версиях переименован в RollingCurlRequest.

  32. №3969
    Sasha
    Sasha 26.02.2011, 12:36:21

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

  33. №4057
    Raimond
    Raimond 10.03.2011, 0:53:14

    замерял время выполнения 2 скриптов 1: при помощи RollingCurl запросить 10 страниц с удаленного сервера (в 10 потоков) 2: то же самое, но при помощи обычного curl в 1 поток.

    результат - прирост скорости ~20% в пользу RollingCurl

  34. №6918
    Макс
    Макс 28.10.2012, 2:23:51

    2Sasha

    Для подмены useragent и proxy подойдёт AngryCurl - улучшенная версия Rolling Curl на php.

  35. №7047
    Shua
    Shua 15.11.2012, 17:20:17

    Что-то не хочет у меня пример работать. В $response - NULL :( Подскажите плз, в чем проблема

  36. №8870
    seyfer
    seyfer 13.03.2014, 13:00:55

    Каким образом можно присоединиться к поддержке?

  37. №8871
    seyfer
    seyfer 13.03.2014, 13:07:56

    Снимаю свой вопрос. Вот более доработанная версия с композером и psr0

    github.com/chuyskywalker/rolling-curl

  38. №8874
    Sam
    Sam 13.03.2014, 15:38:01

    Делали бы уж сразу PSR-4.

  39. №10429
    Сергей
    Сергей 01.04.2016, 10:48:14

    Здравствуйте! Скрипт RollingCurl еще поддерживаете?

  40. №10430
    Sam
    Sam 01.04.2016, 16:03:50

    Нет.

  41. №10431
    Сергей
    Сергей 01.04.2016, 16:11:52

    Можете порекомендовать что-то подобное?

  42. №10432
    Sam
    Sam 01.04.2016, 18:43:59

    Нет. Я давно не занимался этой темой.

  1. Почта опубликована не будет.

  2. Можно использовать синтаксис Markdown или HTML.

  3. Введите ответ в поле. Щёлкните, чтобы получить другую задачу.