Как ускорить cURL в php?

Я пытаюсь встроить твит из Твиттера. Итак, я использую cURL, чтобы вернуть json. Я написал небольшой тест, но он занимает около 5 секунд, как и при локальном запуске. Итак, я не уверен, что я здесь делаю не так.

public function get_tweet_embed($tw_id) {

    $json_url = "https://api.twitter.com/1/statuses/oembed.json?id={$tw_id}&align=left&omit_script=true&hide_media=false";

    $ch = curl_init( $json_url );
    $start_time = microtime(TRUE);
    $JSON = curl_exec($ch);
    $end_time = microtime(TRUE);
    echo $end_time - $start_time; //5.7961111068726

    return $this->get_html($JSON);
}

private function get_html($embed_json) {
    $JSON_Data = json_decode($embed_json,true);
    $tw_embed_code = $JSON_Data["html"];
    return $tw_embed_code;
}

Когда я вставляю ссылку и проверяю ее в браузере, это очень быстро.


person toy    schedule 19.10.2013    source источник


Ответы (7)


Что касается среды, я заметил в PHP, что cURL обычно работает очень быстро в большинстве сред, за исключением мест, где низкий процессор и более низкая производительность сети. Например, на localhost в моей установке MAMP curl работает быстро, на более крупном экземпляре Amazon curl работает быстро. Но на небольшом дрянном хостинге я видел, что у него проблемы с производительностью, когда подключение заметно медленнее. Хотя я не совсем уверен, почему так медленнее. Кроме того, это точно не было на 5 секунд медленнее.

чтобы определить, является ли это PHP или ваша среда, вам следует попробовать взаимодействовать с curl через командную строку. По крайней мере, вы сможете исключить проблему с PHP-кодом, если это еще 5 секунд.

person Kristian    schedule 19.10.2013
comment
Вы были правы, похоже, проблема в DNS. Теперь это быстрее. - person toy; 21.10.2013

Лучшее ускорение, которое у меня когда-либо было, - это повторное использование одной и той же ручки для завивки. Замените $ch = curl_init( $json_url ); на curl_setopt($ch, CURLOPT_URL, $url);. Тогда вне функций есть один $ch = curl_init();. Вам нужно сделать $ch глобальным в функциях для доступа к нему.

Повторное использование дескриптора curl сохраняет соединение с сервером открытым. Это работает, только если сервер между запросами такой же, как и ваш.

person Michael Ozeryansky    schedule 24.12.2015
comment
Я могу убедиться, что это решение сократило общее время выполнения с 22 до 7 секунд (~ 30 вызовов API). Лучше ускориться. Спасибо! Вместо того, чтобы использовать глобальную область видимости, я установил ее как свойство моего класса. - person Thoracius Appotite; 15.02.2018
comment
Спасибо! Повторное использование ручки завитка было для меня уловкой. - person Julian Rios; 20.09.2020
comment
спасибо, код @Michael Sivolobov, реализующий эту идею, мне помогает - person ZaFaR97; 16.10.2020

Окончательное решение для ускорения - это

curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );

С Уважением

person CoverUp    schedule 26.10.2014
comment
почему это должно быть быстрее? - person themhz; 29.01.2015
comment
Я не заметил никаких улучшений с этой опцией - person adrien54; 11.02.2015
comment
Это должно быть реальное решение, хотя, если система настроена правильно, curl будет работать нормально, в противном случае разрешение ipv6 занимает слишком много времени, а затем возвращается к ipv4. - person Soul_man; 30.11.2015
comment
Это решило мою проблему, запрос занимал около 6 секунд, примерно до 1 секунды. - person mewm; 02.02.2016

Попробуйте установить curl_setopt($ch, CURLOPT_ENCODING, '') это включить сжатие gzip

person ncs    schedule 19.10.2013
comment
Это все еще не быстрее, чем раньше. :-( - person toy; 19.10.2013
comment
Попробуйте загрузить страницу с другого сайта, возможно, проблема на локальном веб-сервере. - person ncs; 19.10.2013
comment
есть способ проверить это? Я использую Apache 2 на Centos 5.8 - person toy; 19.10.2013
comment
Мне кажется, что с этими параметрами на 50% быстрее, но я думаю, это будет зависеть от размера вашего ответа. Мой запрос представляет собой файл размером 500 КБ, gziped это 22 КБ, поэтому он ускоряет передачу для меня. Если ваш ответ очень маленький, gzip может оказаться бесполезным, потому что он будет такого же размера и будет передаваться за одно и то же время. Спасибо ncs - person adrien54; 11.02.2015
comment
Подробнее об этом ответе можно узнать здесь: stackoverflow.com/questions/310650/ - person degenerate; 31.07.2019

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

Мне нужно было обрабатывать около 1 миллиона сущностей каждый день с одного API-сервера, что ограничивает нас возможностью использовать только одно одновременное соединение. Я создал этот класс. Я надеюсь, что это поможет другим в оптимизации их запросов на завитки.

class ApiClient
{
    const CURL_TIMEOUT = 3600;
    const CONNECT_TIMEOUT = 30;
    const HOST = 'api.example.com';
    const API_TOKEN = 'token';

    /** @var resource CURL handler. Reused every time for optimization purposes */
    private $ch;
    /** @var string URL for API. Calculated at creating object for optimization purposes */
    private $url;

    public function __construct()
    {
        $this->url = 'https://' . self::HOST . '/v1/entity/view?token=' . self::API_TOKEN . '&id=';
                                // Micro-optimization: every concat operation takes several milliseconds
                                // But for millions sequential requests it can save a few seconds
        $host = [implode(':', [ // $host stores information for domain names resolving (like /etc/hosts file)
            self::HOST, // Host that will be stored in our "DNS-cache"
            443, // Default port for HTTPS, can be 80 for HTTP
            gethostbyname(self::HOST), // IPv4-address where to point our domain name (Host)
        ])];
        $this->ch = curl_init();
        curl_setopt($this->ch, CURLOPT_ENCODING, '');  // This will use server's gzip (compress data)
                                                       // Depends on server. On some servers can not work
        curl_setopt($this->ch, CURLOPT_RESOLVE, $host); // This will cut all requests for domain name resolving
        curl_setopt($this->ch, CURLOPT_TIMEOUT, self::CURL_TIMEOUT); // To not wait extra time if we know
                                                            // that api-call cannot be longer than CURL_TIMEOUT
        curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, self::CONNECT_TIMEOUT); // Close connection if server doesn't response after CONNECT_TIMEOUT
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true); // To return output in `curl_exec`
    }

    /** @throws \Exception */
    public function requestEntity($id)
    {
        $url = $this->url . $id;

        curl_setopt($this->ch, CURLOPT_URL, $url);

        $data = curl_exec($this->ch);

        if (curl_error($this->ch)) {
            throw new \Exception('cURL error (' . curl_errno($this->ch) . '): ' . curl_error($this->ch));
        }

        return $data;
    }

    public function __destruct()
    {
        curl_close($this->ch);
    }
}

Также, если у вас нет ограничений на одно соединение с сервером, вы можете использовать curl_multi_* функции.

person Michael Sivolobov    schedule 14.11.2018
comment
Спасибо за этот фрагмент кода, он очень полезен. ускорить мои запросы 30% + - person ZaFaR97; 16.10.2020
comment
У меня есть проблемы с этим подходом. В частности, я не могу найти информацию о том, как правильно сбросить ранее установленные параметры (например, CURLOPT_COOKIEFILE, CURLOPT_POSTFIELDS и т. Д.). В настоящее время (новый $ curl для каждого запроса) - я просто не устанавливаю эти параметры, если они не нужны для текущего запроса =) - person pilat; 11.02.2021
comment
Если у вас очень разные запросы, вы не должны использовать этот код, так как он оптимизирован для похожих запросов. - person Michael Sivolobov; 12.02.2021

Пытаться

CURLOPT_TCP_FASTOPEN => 1

... для активации TCP-Fast-Open.

Он был добавлен в cURL 7.49.0, добавлен в PHP 7.0.7.

person Frank    schedule 27.09.2019
comment
как это установить именно в PHP? - person Kahlil N; 30.04.2021

Попробуйте использовать с параметром --ipv4.

Это заставит curl использовать только ipv-4 и игнорировать ipv-6, который все еще не очень совместим с некоторыми устройствами и замедляет процесс. Добавление --ipv4 в мою команду curl снизило затраты с 8 до 4 секунд. Что на 50% быстрее.

person mustafa candan    schedule 18.10.2018