Класс MultiCurl

Статус
В этой теме нельзя размещать новые ответы.

Jeurey

Хранитель порядка
Регистрация
13 Сен 2006
Сообщения
419
Реакции
614
Хм. Интересно... Дай-ка код или опиши что конкретно пытаешься сделать.
 

KillDead

Хранитель порядка
Регистрация
11 Авг 2006
Сообщения
894
Реакции
579
Была ли попытка связать эту библиотеку с работой с ftp? Я Попытался, но переодически библиотека убивает апач- один и тотже скрипт то вылетает, то выполняется без помех.
В общем тестил на 2-х машинах на пхп версии 5.2. После перехода на 5.3 всё заработало.
------------
Те, кто пользуется этой (да и многими другими обёртками к курлу) заметили что сдесь реализованы блокирующие соединения- скрипт ждёт окончания всех паралельных коннектов и только потом возвращает управление, соответственно если у тебя хоть один сервак не отвечает - вся пачка будет висеть и ждать, пока он не отвалится по таймауту.
В инете есть реализации неблокирующих соединений, но после попытки использовать их в работе возвратился к данному классу. Тк он стабильнее в работе и в общем лучше написан (как мне показалось).
Тем более чтобы реализовать необходимое в данном классе необходимы минимальные телодвижения, нужно всего переопределить getUrls() функцию и добавить ещё одну для задания имени callback функции:
PHP:
    /**
     *  Получение содержимого из списка урлов в массив
     * @return array $results
     */
    public function getUrls() {
        if(!sizeof($this->_urls)) {
            return self::E_EMPTY_URLS_LIST;
        }
        $results    = array();
        while(true) {
            // Создание потоков
            while ($this->_threadsRunning < $this->_threadsCount && sizeof($this->_urls)) {  //
                $url_end = end($this->_urls);
                $url_end_key = key($this->_urls);
                #echo "ADD: {$url_end}\n" ;  flush();
                $this->_createThread();
                end($this->_curlHandles);
                $this->_threadId_connect[key($this->_curlHandles)] = $url_end_key;              
                $this->_threadsRunning++;
            }
            // Проверка на выполненность
            if ($this->_threadsRunning == 0 && !sizeof($this->_urls) ) {
                break;
            }
            // Let mcurl do it's thing
            curl_multi_select($this->_curlMultiHandle);
            while(($mcRes = curl_multi_exec($this->_curlMultiHandle, $mcActive)) == CURLM_CALL_MULTI_PERFORM) {
                usleep($this->_usleepTime);
            }
            if($mcRes != CURLM_OK) {
                break;
            }
            while($threadInfo = curl_multi_info_read($this->_curlMultiHandle)) {
                $threadResult   = array('errors' => false, 'url' => false, 'contents' => false);
                $threadId   = (string) $threadInfo['handle'];
                $threadResult['url']        = curl_getinfo($this->_curlHandles[$threadId],  CURLINFO_EFFECTIVE_URL);
                #echo "LOADING: {$threadResult['url']}\n" ;     flush();
                $threadResult['threadId']   = $this->_threadId_connect[$threadId];
                $threadResult['errors']     = curl_error($this->_curlHandles[$threadId]);
                $threadResult['contents']   = curl_multi_getcontent($this->_curlHandles[$threadId]);
                $threadResult['curlinfo']   = $this->_curlObjects[$threadId]->getOptions();
                $results[$threadId] = $threadResult;
                call_user_func( $this->_postProccesingFunc, $threadResult);
                $this->_killThread($threadId);
                $this->_threadsRunning--;
            }
        }
        return $results;
    }

    public $_threadId_connect = array();

// установка callback функции
    public function setProcessing($post) {
        $this->_postProccesingFunc = $post;
    }
Пример
PHP:
   for($i=0; $i<20; $i++) {
 
            $urls['url'][]= 'http://proekt/pi_multicurl/samples/chek.php?x=index()_'.$i;
 
    }
    $results = array();
    try {
        $cURL =new Pi_MultiCurl_extOptions ( );
    } catch (Pi_MultiCurl_Exception $e) {
        echo $e->getMessage();
        exit();
    }
    define('URL_STACK_SIZE',  5 );
    $cURL->setThreadsCount(URL_STACK_SIZE);
    $cURL->setThreadTimeout(30);
    $cURL->setUsleepTime(600);
// функция обработки полученных данных
    function rollingPost($thread) {
        echo  "Это {$thread['threadId']}-й элемент \$urls['url']CONTENT: ".$thread['contents'];
        flush();
    }
        $cURL->setProcessing( "rollingPost");
        $cURL->setUrls($urls['url']);
        $cURL->getUrls();
Вроде ничего не забыл. Для обратной совместимости добавил $thread['threadId']. Он указывает на ключ элемента, взятого из массива $urls['url'].
 

-=BlackSmoke=-

Профессор
Регистрация
4 Авг 2009
Сообщения
280
Реакции
49
Jeurey, запости, пожалуйста, пример с работой с куками :)
 

-=BlackSmoke=-

Профессор
Регистрация
4 Авг 2009
Сообщения
280
Реакции
49
и что будет, если внутри одного потока открыть обычный курл?
 

stargazerrrrr

Fearless
Регистрация
9 Дек 2009
Сообщения
231
Реакции
82
Я для этих целей rolling curl юзаю. Позволяет параллельное выполнение большого количества асинхронных HTTP-запросов при помощи curl. Правильно чистит память, не простаивает зря, выполняя одновременно заданное число запросов. Обрабатывает каждый ответ сразу после выполнения запроса.


Кстати автор этого класса - известный кодер Sam Dark, один из ведущих разработчиков на основе yii фреймворка.

Пример
PHP:
// an array of URL's to fetch
$urls = array("http://www.google.com",
              "http://www.facebook.com",
              "http://www.yahoo.com");

// a function that will process the returned responses
function request_callback($response, $info, $request) {
	// parse the page title out of the returned HTML
	if (preg_match("~<title>(.*?)</title>~i", $response, $out)) {
		$title = $out[1];
	}
	echo "<b>$title</b><br />";
	print_r($info);
	echo "<hr>";
}

// create a new RollingCurl object and pass it the name of your custom callback function
$rc = new RollingCurl("request_callback");
// the window size determines how many simultaneous requests to allow.
$rc->window_size = 20;
foreach ($urls as $url) {
    // add each request to the RollingCurl object
    $request = new RollingCurlRequest($url);
    $rc->add($request);
}
$rc->execute();
 

kactetus

митя is here )
Регистрация
26 Авг 2007
Сообщения
440
Реакции
280
Нормально

stargazerrrrr класс вроде не плохой, сам пользуешся? как по стабильности?

Отчет по работе класса.
Сам щас тестил загнал 3138 урлов.
Время работы 570 сек. + сохранял каждый результат (title) в txt файл.
Скорость инета 3 мбит/с
 

stargazerrrrr

Fearless
Регистрация
9 Дек 2009
Сообщения
231
Реакции
82
Пользуюсь конечно. Советую поиграться с параметром window_size (кол-во параллельных потоков), чтобы забить канал под завязку.

У меня на средненьком VPS на 100 потоках работает вот так:

Number of proxies in list: 1372
Checking time: 33.446796 sec.(or 0.5574466 min)
41.0203715776 proxies a second
 

kactetus

митя is here )
Регистрация
26 Авг 2007
Сообщения
440
Реакции
280
Jeurey По поводу Pi_MultiCurl класс еще развивается?
Где можно скачать данный класс а то ни сайт, ни файлов НЕТ.

stargazerrrrr как выставить правильно timeout на соединие в потоке?
Параметром $rc->window_size = 20; - выставляем количество потоков.

Заглянув в код класса, посмотрел что есть переменная timeout, по аналогии выставляю $rc->timeout = 10; правильно ли?
Просто есть парсер картинок, хочу добавить в него мультипоточность, так получается что некоторые картинки не доконца докачиваются или не могут открыться.
 

KillDead

Хранитель порядка
Регистрация
11 Авг 2006
Сообщения
894
Реакции
579
Jeurey По поводу Pi_MultiCurl класс еще развивается?
Где можно скачать данный класс а то ни сайт, ни файлов НЕТ.
Хз, развивается ли, думаю только для своих проектах, т.к. много в нём нет, но и сейчас данный класс неплохо написан. Я всё хочу довести до ума свай класс и выложить, или хотя бы переделанный pi_curl, но всё руки не доходят да и постоянно баги новые появляются.
Вот примитивные тесты, обычный гет запрос:
1- мой класс
2- rc
количество запросов 100 потоков 5
1 [time] => 4.908
2 [time] => 4.1403
количество запросов 100 потоков 50
1 [time] => 3.8969
2 [time] => 1.9794
количество запросов 1000 потоков 50
1 [time] => 7.5136
2 [time] => 9.8128
количество запросов 1000 потоков 100
1 [time] => 4.8728
2 [time] => 13.4546

Вообще, настоящие тесты нужно было бы провести (включить куки, пост, выдать на каждые чётные запросы ошибку и посмотреть не затормозит ли класс), возможно позже, а сейчас:
О скорости ничего хорошего сказать не могу- мой класс построен на Pi_MultiCurl, который довольно сильно изменён, и включает в себя ещё кучу разных проверок, генераций, переопределений, а чистая библиотека rc - ему проигрывает. Очень не хорошо. Хотя в принципе, порой не так критично- ну будет парсится сайт не час, а полтора часа.
О памяти - вот в чём скорее всего выигрывает rc. Если в мой класс загрузить очень много ссылок кучей- память будет утекать. Но пока не нужно обрабатывать 500к ссылок за раз- можно не парится.
 

kactetus

митя is here )
Регистрация
26 Авг 2007
Сообщения
440
Реакции
280
KillDead а можеш поделится, хотел бы глянуть на него :), если не жалко. Хотелось бы глянуть как постороен данный класс.
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху