Класс MultiCurl

Статус
В этой теме нельзя размещать новые ответы.
Хм. Интересно... Дай-ка код или опиши что конкретно пытаешься сделать.
 
Была ли попытка связать эту библиотеку с работой с 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'].
 
Jeurey, запости, пожалуйста, пример с работой с куками :)
 
и что будет, если внутри одного потока открыть обычный курл?
 
Я для этих целей 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();
 
Нормально

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

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

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

Number of proxies in list: 1372
Checking time: 33.446796 sec.(or 0.5574466 min)
41.0203715776 proxies a second
 
Jeurey По поводу Pi_MultiCurl класс еще развивается?
Где можно скачать данный класс а то ни сайт, ни файлов НЕТ.

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

Заглянув в код класса, посмотрел что есть переменная timeout, по аналогии выставляю $rc->timeout = 10; правильно ли?
Просто есть парсер картинок, хочу добавить в него мультипоточность, так получается что некоторые картинки не доконца докачиваются или не могут открыться.
 
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к ссылок за раз- можно не парится.
 
KillDead а можеш поделится, хотел бы глянуть на него :), если не жалко. Хотелось бы глянуть как постороен данный класс.
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху