Возможно ли выполнение асинхронных HTTP-запросов с помощью PHP? - PullRequest
35 голосов
/ 28 марта 2011

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

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

Ответы [ 5 ]

21 голосов
/ 25 ноября 2012

Выезд 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();
17 голосов
/ 28 марта 2011

Да.

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

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

1 голос
/ 06 февраля 2015

Библиотека @ 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; "myemail@gmail.com" =>
     * &nbsp; "http://someapi.com/results?search=easylife",<br />
     * &nbsp; "michael@gmail.com" =>
     * &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; "myemail@gmail.com" => <br />
     * &nbsp; "Work less, enjoy more",<br />
     * &nbsp; "michael@gmail.com" => <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;
    }
0 голосов
/ 29 декабря 2016

В 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 мс*

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

0 голосов
/ 21 июля 2016

Для PHP5.5 +, mpyw / co является окончательным решением.Он работает так, как если бы он был tj / co в JavaScript.

Пример

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

  1. Получить содержимое http://github.com/mpyw (GET HTML)
  2. Найти <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 это очень просто.Для получения более подробной информации посетите страницу хранилища.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...