Какой самый быстрый способ очистить множество страниц в php? - PullRequest
2 голосов
/ 20 мая 2010

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

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

Выполнение запроса multi curl в простом цикле while выполняется довольно медленно. Я ускорил его, выполнив отдельные запросы curl в фоновом процессе, который работает быстрее, но рано или поздно более медленные запросы начинают накапливаться, что приводит к сбою сервера.

Существуют ли более эффективные способы очистки данных? возможно, командная строка curl?

Ответы [ 3 ]

2 голосов
/ 20 мая 2010

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

В прошлый раз, когда я играл с потоками PHP, это был не слишком удачный вариант, но, возможно, это изменилось. Если вам нужно придерживаться PHP, это означает, что вы будете вынуждены использовать многопроцессный подход: разделите вашу рабочую нагрузку на N рабочих блоков и запустите N экземпляров вашего скрипта, каждый из которых получает 1 рабочий блок.

Языки, которые обеспечивают надежные и хорошие реализации потоков, являются еще одним вариантом. У меня был хороший опыт работы с потоками в ruby ​​и C, и кажется, что потоки Java также очень зрелые и надежные.

Кто знает - возможно, потоки PHP улучшились с тех пор, как я в последний раз играл с ними (~ 4 года назад), и стоит посмотреть.

0 голосов
/ 21 мая 2010

Если вы хотите запускать одиночные запросы curl, вы можете запускать фоновые процессы под Linux в PHP, например:

proc_close ( proc_open ("php -q yourscript.php parameter1 parameter2 & 2> /dev/null 1> /dev/null", array(), $dummy ));

Вы можете использовать параметры, чтобы дать вашему php-скрипту некоторую информацию о том, что использовать, например LIMIT в sql.

Вы можете отслеживать запущенные процессы, сохраняя их PID где-нибудь, чтобы поддерживать требуемое количество процессов, запущенных одновременно, или уничтожать процессы, которые не были завершены вовремя.

0 голосов
/ 20 мая 2010

По моему опыту, выполнение запроса curl_multi с фиксированным числом потоков - это самый быстрый способ, не могли бы вы поделиться используемым кодом, чтобы мы могли предложить некоторые улучшения? Этот ответ имеет довольно приличную реализацию curl_multi с многопоточным подходом. Вот воспроизводимый код:

// -- create all the individual cURL handles and set their options
$curl_handles = array();
foreach ($urls as $url) {
    $curl_handles[$url] = curl_init();
    curl_setopt($curl_handles[$url], CURLOPT_URL, $url);
    // set other curl options here
}

// -- start going through the cURL handles and running them
$curl_multi_handle = curl_multi_init();

$i = 0; // count where we are in the list so we can break up the runs into smaller blocks
$block = array(); // to accumulate the curl_handles for each group we'll run simultaneously

foreach ($curl_handles as $a_curl_handle) {
    $i++; // increment the position-counter

    // add the handle to the curl_multi_handle and to our tracking "block"
    curl_multi_add_handle($curl_multi_handle, $a_curl_handle);
    $block[] = $a_curl_handle;

    // -- check to see if we've got a "full block" to run or if we're at the end of out list of handles
    if (($i % BLOCK_SIZE == 0) or ($i == count($curl_handles))) {
        // -- run the block

        $running = NULL;
        do {
            // track the previous loop's number of handles still running so we can tell if it changes
            $running_before = $running;

            // run the block or check on the running block and get the number of sites still running in $running
            curl_multi_exec($curl_multi_handle, $running);

            // if the number of sites still running changed, print out a message with the number of sites that are still running.
            if ($running != $running_before) {
                echo("Waiting for $running sites to finish...\n");
            }
        } while ($running > 0);

        // -- once the number still running is 0, curl_multi_ is done, so check the results
        foreach ($block as $handle) {
            // HTTP response code
            $code = curl_getinfo($handle,  CURLINFO_HTTP_CODE);

            // cURL error number
            $curl_errno = curl_errno($handle);

            // cURL error message
            $curl_error = curl_error($handle);

            // output if there was an error
            if ($curl_error) {
                echo("    *** cURL error: ($curl_errno) $curl_error\n");
            }

            // remove the (used) handle from the curl_multi_handle
            curl_multi_remove_handle($curl_multi_handle, $handle);
        }

        // reset the block to empty, since we've run its curl_handles
        $block = array();
    }
}

// close the curl_multi_handle once we're done
curl_multi_close($curl_multi_handle);

Хитрость заключается в том, чтобы не загружать слишком много URL-адресов одновременно, есличто весь процесс будет зависать, пока не будут выполнены более медленные запросы.Я предлагаю использовать BLOCK_SIZE из 8 или выше, если у вас есть пропускная способность.

...