Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guzzle HTTP Client is slower than Symfony HTTP Client

This may be opinion based question.

I want to use Guzzle HTTP Client as many suggest that its better than Symfony HTTP Client, also Cloudflare uses Guzzle HTTP Client in its PHP Api. However, I performed a simple test using Symfony HTTP Client and Guzzle HTTP Client. The result suggests that Guzzle HTTP Client is much slower than Symfony HTTP Client.

I want to know / understand that why with such renowned reputation Guzzle HTTP Client lacks speed. Or is there something that I am doing wrong.

composer.json

{
    "require": {
        "php": "7.4.*",
        "symfony/http-client": "^5.0",
        "guzzlehttp/guzzle": "^6.5"
    }
}

test.php

<?php
echo "<pre>\n";
require_once(__DIR__ . DIRECTORY_SEPARATOR . '../vendor/autoload.php');

$url = 'http://192.168.1.81';
$tSElaspedTotal = 0;
$tGElaspedTotal = 0;
$tCElaspedTotal = 0;
$iterations = 10;
for ($i = 1; $i <= $iterations; $i++) {
    unset($tSElasped, $tSStart, $tSEnd, $httpS, $httpSOpt, $curlS);
    unset($tGElasped, $tGStart, $tGEnd, $httpG, $httpGOpt, $curlG);
    unset($tCElasped, $tCStart, $tCEnd, $httpC, $httpCOpt, $curlC);

    $tSElasped = $tGElasped = $tCElasped = 0;

    $httpS = new \Symfony\Component\HttpClient\CurlHttpClient();
    $httpSOpt = [
        'headers' => [
            'User-Agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13',
        ],
        'timeout' => 30,
    ];
    echo "\nSymfony Http Client Start: " . $tSStart = microtime(true);
    $curlS = $httpS->request('GET', $url, $httpSOpt);
    echo "\nSymfony Http Client End: " . $tSEnd = microtime(true);

    $httpG = new \GuzzleHttp\Client();
    $httpGOpt = [
        'headers' => [
            'User-Agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13',
        ],
        'force_ip_resolve' => 'v4',
        'timeout' => 30,
    ];
    echo "\nGuzzle Http Client Start: " . $tGStart = microtime(true);
    $curlG = $httpG->request('GET', $url, $httpGOpt);
    echo "\nGuzzle Http Client End: " . $tGEnd = microtime(true);

    $httpC = curl_init();
    curl_reset($httpC);
    $httpCOpt = [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FRESH_CONNECT => true,
        CURLOPT_FORBID_REUSE => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
    ];
    $httpCOpt[CURLOPT_URL] = $url;
    curl_setopt_array($httpC, $httpCOpt);
    echo "\nPHP Curl Start: " . $tCStart = microtime(true);
    $curlC = curl_exec($httpC);
    echo "\nPHP Curl End: " . $tCEnd = microtime(true);

    $tSElasped = ($tSEnd - $tSStart);
    $tSElaspedTotal += $tSElasped;
    $tGElasped = ($tGEnd - $tGStart);
    $tGElaspedTotal += $tGElasped;
    $tCElasped = ($tCEnd - $tCStart);
    $tCElaspedTotal += $tCElasped;
    echo "\n({$i}) - Time Elasped\n";
    echo "\nSymfony: \t" . $tSElasped . "\nGuzzle: \t" . $tGElasped . "\nCurl: \t\t" . $tCElasped . "<hr>";
}

echo "\nToal Time Elasped\n";
echo "\nSymfony: \t" . ($tSElaspedTotal / $iterations) . "\nGuzzle: \t" . ($tGElaspedTotal / $iterations) . "\nCurl: \t\t" . ($tCElaspedTotal / $iterations) . "<hr>";

My Results

Symfony Http Client Start: 1587377963.6117
Symfony Http Client End: 1587377963.6118
Guzzle Http Client Start: 1587377963.6119
Guzzle Http Client End: 1587377963.6302
PHP Curl Start: 1587377963.6302
PHP Curl End: 1587377963.6467
(1) - Time Elasped

Symfony:    0.00014400482177734
Guzzle:     0.018287897109985
Curl:       0.01648998260498

Symfony Http Client Start: 1587377963.6598
Symfony Http Client End: 1587377963.6599
Guzzle Http Client Start: 1587377963.6599
Guzzle Http Client End: 1587377963.6766
PHP Curl Start: 1587377963.6766
PHP Curl End: 1587377963.6911
(2) - Time Elasped

Symfony:    8.2015991210938E-5
Guzzle:     0.016661882400513
Curl:       0.014525175094604

Symfony Http Client Start: 1587377963.6978
Symfony Http Client End: 1587377963.6979
Guzzle Http Client Start: 1587377963.6979
Guzzle Http Client End: 1587377963.7114
PHP Curl Start: 1587377963.7114
PHP Curl End: 1587377963.7245
(3) - Time Elasped

Symfony:    9.0122222900391E-5
Guzzle:     0.013462066650391
Curl:       0.013139009475708

Symfony Http Client Start: 1587377963.7316
Symfony Http Client End: 1587377963.7317
Guzzle Http Client Start: 1587377963.7317
Guzzle Http Client End: 1587377963.7461
PHP Curl Start: 1587377963.7461
PHP Curl End: 1587377963.761
(4) - Time Elasped

Symfony:    8.2015991210938E-5
Guzzle:     0.014389991760254
Curl:       0.014890909194946

Symfony Http Client Start: 1587377963.7676
Symfony Http Client End: 1587377963.7677
Guzzle Http Client Start: 1587377963.7677
Guzzle Http Client End: 1587377963.7861
PHP Curl Start: 1587377963.7861
PHP Curl End: 1587377963.8006
(5) - Time Elasped

Symfony:    8.7976455688477E-5
Guzzle:     0.018366098403931
Curl:       0.014465093612671

Symfony Http Client Start: 1587377963.8074
Symfony Http Client End: 1587377963.8075
Guzzle Http Client Start: 1587377963.8075
Guzzle Http Client End: 1587377963.8244
PHP Curl Start: 1587377963.8244
PHP Curl End: 1587377963.8385
(6) - Time Elasped

Symfony:    7.9870223999023E-5
Guzzle:     0.016865968704224
Curl:       0.014086961746216

Symfony Http Client Start: 1587377963.8467
Symfony Http Client End: 1587377963.8468
Guzzle Http Client Start: 1587377963.8468
Guzzle Http Client End: 1587377963.8625
PHP Curl Start: 1587377963.8625
PHP Curl End: 1587377963.8773
(7) - Time Elasped

Symfony:    8.4877014160156E-5
Guzzle:     0.015748023986816
Curl:       0.014772891998291

Symfony Http Client Start: 1587377963.8842
Symfony Http Client End: 1587377963.8843
Guzzle Http Client Start: 1587377963.8843
Guzzle Http Client End: 1587377963.8971
PHP Curl Start: 1587377963.8971
PHP Curl End: 1587377963.9111
(8) - Time Elasped

Symfony:    8.4877014160156E-5
Guzzle:     0.012855052947998
Curl:       0.013998985290527

Symfony Http Client Start: 1587377963.9213
Symfony Http Client End: 1587377963.9214
Guzzle Http Client Start: 1587377963.9214
Guzzle Http Client End: 1587377963.9339
PHP Curl Start: 1587377963.9339
PHP Curl End: 1587377963.9464
(9) - Time Elasped

Symfony:    8.392333984375E-5
Guzzle:     0.012518882751465
Curl:       0.012485980987549

Symfony Http Client Start: 1587377963.9528
Symfony Http Client End: 1587377963.9529
Guzzle Http Client Start: 1587377963.9529
Guzzle Http Client End: 1587377963.9708
PHP Curl Start: 1587377963.9708
PHP Curl End: 1587377963.985
(10) - Time Elasped

Symfony:    7.7962875366211E-5
Guzzle:     0.017860889434814
Curl:       0.014163017272949

Toal Time Elasped

Symfony:    8.9764595031738E-5
Guzzle:     0.015701675415039
Curl:       0.014301800727844

OS and Other Details.

  1. Ubuntu 18.04.4 LTS in HyperV on Windows 10 version 1909
  2. Curl Version 7.58 (7.58.0-2ubuntu3.8)
  3. PHP Version 7.4.5 (7.4.5-1+ubuntu18.04.1+deb.sury.org+1)
  4. PHP FPM Version 7.4 (7.4.5-1+ubuntu18.04.1+deb.sury.org+1)
  5. PHP Curl Version 7.4 (7.4.5-1+ubuntu18.04.1+deb.sury.org+1)

Change 1

Update:

I have edited my code in test.php to

  1. Include PHP Curl to the mix.
  2. Added loop for multiple co-current requests.
  3. Used address of another server on local network as test site, because many site will block on multiple co-current requests.
  4. Properly reset all variables instead of just re-assigning.

Finding: There is a hell lot of difference in timings after changing the code. However, still confused about why this happened even though this was pointed out to me.

But in the end as Guzzle HTTP Client's timings (which seems realistic) are close to PHP Curl, and as Guzzle HTTP Client handles HTTP Errors different than Symfony HTTP Client and throws exception at fetching url instead of at the result fetching.

I think that Guzzle HTTP Client will be much better suited for my project than Symfony HTTP Client.

like image 892
Umair Khan Avatar asked Apr 20 '20 08:04

Umair Khan


1 Answers

That's because the Symfony Client executes the request not on $http->request(). This is done when it is required the first time.

When you change your code for both test cases you see the time difference melt away

...
$response = $http->request($method, $url, $httpOpt);
return $response->getStatusCode();

When checking your results for plausibility you should have noticed that the times before are impossible to achieve.

My tests before the fix where
Symfony: 0.00944495201
Guzzle: 0.18365287780

The Symfony result is faster than any simple network ping

like image 179
Bernhard Avatar answered Nov 15 '22 06:11

Bernhard