Подтвердить что ты не робот

Выполняет ли асинхронные HTTP-запросы с PHP?

У меня есть PHP script, которому необходимо загрузить несколько файлов с удаленного сервера. На данный момент у меня просто есть цикл загрузки и обработки файлов с помощью cURL, что означает, что он не запускает загрузку одного файла до тех пор, пока предыдущий не будет завершен - это значительно увеличивает время выполнения script.

Можно ли запустить несколько экземпляров cURL, например, для асинхронной загрузки этих файлов одновременно, не дожидаясь завершения предыдущего? Если да, то как это будет выполнено?

4b9b3361

Ответ 1

Да.

Существует многозадачная библиотека PHP (или смотрите: заархивировано Проект Google Code). Это многопоточная библиотека CURL.

В качестве другого решения вы можете написать script, который делает это на языке, который поддерживает потоки, такие как Ruby или Python. Затем просто вызовите script с помощью PHP. Кажется довольно простым.

Ответ 2

Отъезд curl-easy. Он поддерживает как блокирующие, так и неблокирующие запросы одновременно или по одному запросу. Кроме того, он протестирован с помощью модуля, в отличие от многих простых или багги-библиотек.

Раскрытие информации: Я являюсь автором этой библиотеки. В библиотеке есть собственный набор тестов, поэтому я уверен, что он надежный.

Кроме того, посмотрите пример использования ниже:

<?php
// We will download info about 2 YouTube videos:
// http://youtu.be/XmSdTa9kaiQ and
// http://youtu.be/6dC-sm5SWiU

// Init queue of requests
$queue = new cURL\RequestsQueue;
// Set default options for all requests in queue
$queue->getDefaultOptions()
    ->set(CURLOPT_TIMEOUT, 5)
    ->set(CURLOPT_RETURNTRANSFER, true);
// Set callback function to be executed when request will be completed
$queue->addListener('complete', function (cURL\Event $event) {
    $response = $event->response;
    $json = $response->getContent(); // Returns content of response
    $feed = json_decode($json, true);
    echo $feed['entry']['title']['$t'] . "\n";
});

$request = new cURL\Request('http://gdata.youtube.com/feeds/api/videos/XmSdTa9kaiQ?v=2&alt=json');
$queue->attach($request);

$request = new cURL\Request('http://gdata.youtube.com/feeds/api/videos/6dC-sm5SWiU?v=2&alt=json');
$queue->attach($request);

// Execute queue
$queue->send();

Ответ 3

Библиотека @stil - это так здорово. Огромное спасибо ему!

Тем не менее, я написал хорошую функцию утилиты, которая позволяет легко получать асинхронное содержимое из нескольких URL-адресов (API в моем случае) и возвращать их без потери информации, которая есть.

Вы просто запускаете его, передавая ключ = > массив значений в качестве ввода, и он возвращает массив ключей = > ответ: -)

/** 
     * This function runs multiple GET requests parallely.<br />
     * @param array $urlsArray needs to be in format:<br />
     * <i>array(<br />
     * [url_unique_id_1] => [url_for_request_1],<br />
     * [url_unique_id_2] => [url_for_request_2],<br />
     * [url_unique_id_3] => [url_for_request_3]<br />
     * )</i><br />
     * e.g. input like:<br />
     *  <i>array(<br />
     * &nbsp; "[email protected]" =>
     * &nbsp; "http://someapi.com/results?search=easylife",<br />
     * &nbsp; "[email protected]" =>
     * &nbsp; "http://someapi.com/results?search=safelife"<br />
     * )</i>
     * @return array An array where for every <i>url_unique_id</i> response to this request 
     * is returned e.g.<br />
     * <i>array(<br />
     * &nbsp; "[email protected]" => <br />
     * &nbsp; "Work less, enjoy more",<br />
     * &nbsp; "[email protected]" => <br />
     * &nbsp; "Study, work, pay taxes"<br />
     * )</i>
     *  */
    public function getResponsesFromUrlsAsynchronously(array $urlsArray, $timeout = 8) {
        $queue = new \cURL\RequestsQueue;

        // Set default options for all requests in queue
        $queue->getDefaultOptions()
                ->set(CURLOPT_TIMEOUT, $timeout)
                ->set(CURLOPT_RETURNTRANSFER, true);

        // =========================================================================
        // Define some extra variables to be used in callback

        global $requestUidToUserUrlIdentifiers;
        $requestUidToUserUrlIdentifiers = array();

        global $userIdentifiersToResponses;
        $userIdentifiersToResponses = array();

        // =========================================================================

        // Set function to be executed when request will be completed
        $queue->addListener('complete', function (\cURL\Event $event) {

            // Define user identifier for this url
            global $requestUidToUserUrlIdentifiers;
            $requestId = $event->request->getUID();
            $userIdentifier = $requestUidToUserUrlIdentifiers[$requestId];

            // =========================================================================

            $response = $event->response;
            $json = $response->getContent(); // Returns content of response

            $apiResponseAsArray = json_decode($json, true);
            $apiResponseAsArray = $apiResponseAsArray['jobs'];

            // =========================================================================
            // Store this response in proper structure
            global $userIdentifiersToResponses;
            $userIdentifiersToResponses[$userIdentifier] = $apiResponseAsArray;
        });

        // =========================================================================

        // Add all request to queue
        foreach ($urlsArray as $userUrlIdentifier => $url) {
            $request = new \cURL\Request($url);
            $requestUidToUserUrlIdentifiers[$request->getUID()] = $userUrlIdentifier;
            $queue->attach($request);
        }

        // =========================================================================

        // Execute queue
        $queue->send();

        // =========================================================================

        return $userIdentifiersToResponses;
    }

Ответ 4

Для PHP5.5 +, mpyw/co - это окончательное решение. Он работает так, как будто tj/co в JavaScript.

Пример

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

  • Получить контент http://github.com/mpyw (GET HTML)
  • Найти <img class="avatar" src="..."> и запросить его (GET IMAGE)

---: Ожидание ответа

...: Ожидание другого ответа в параллельных потоках

Многие известные сценарии на основе curl_multi уже предоставляют нам следующие потоки.

        /-----------GET HTML\  /--GET IMAGE.........\
       /                     \/                      \ 
[Start] GET HTML..............----------------GET IMAGE [Finish]
       \                     /\                      /
        \-----GET HTML....../  \-----GET IMAGE....../

Однако это недостаточно эффективно. Вы хотите уменьшить количество времени ожидания ...?

        /-----------GET HTML--GET IMAGE\
       /                                \            
[Start] GET HTML----------------GET IMAGE [Finish]
       \                                /
        \-----GET HTML-----GET IMAGE.../

Да, это очень легко с mpyw/co. Подробнее см. на странице репозитория.

Ответ 5

В PHP 7.0 и Apache 2.0, как сказано в PHP exec Document, перенаправляя вывод, добавив " & > /dev/null &" в конце команды, может заставить его работать на фоне, просто не забудьте правильно выполнить команду.

$time = microtime(true);
$command = '/usr/bin/curl -H \'Content-Type: application/json\' -d \'' . $curlPost . '\' --url \'' . $wholeUrl . '\' >> /dev/shm/request.log 2> /dev/null &';
exec($command);
echo (microtime(true) - $time) * 1000 . ' ms';

Выше работает хорошо для меня, занимает всего 3 мс, но следующее не будет работать, занимает 1500 мс.

$time = microtime(true);
$command = '/usr/bin/curl -H \'Content-Type: application/json\' -d \'' . $curlPost . '\' --url ' . $wholeUrl;
exec($command . ' >> /dev/shm/request.log 2> /dev/null &');
echo (microtime(true) - $time) * 1000 . ' ms';

В целом добавление "& > /dev/null &" в конце вашей команды может помочь, просто запомните правильную WRAP свою команду.