Curl's Solution in the Swoole Coprocess

It is well known that Curl is not recommended in SWOLE applications because it blocks processes.

This article will use actual code and data, in the most intuitive way, to let you understand why.

Finally, Curl's solution in Swoole will be given. If you don't want to see the analysis, you can go straight to the end.

Routine comparison

Yu Run doesn't like the empty articles, so she writes them by herself, so she can run the code directly, and use the data to see why Curl is not recommended in Swoole.

In order to be lazy, I used it directly. YurunHttp Surl and Swolle Handler, instead of the long, stinky Curl code.

Code

composer.json

{
    "require": {
        "yurunsoft/yurun-http": "~3.0"
    }
}

server.php

<?php
$http = new Swoole\Http\Server('127.0.0.1', 9501);
$http->on('workerstart', function(){
    \Swoole\Runtime::enableCoroutine();
});
$http->on('request', function ($request, $response) {
    sleep(1); // Assuming that various processes take 1 second
    $response->end($request->get['id'] . ': ' . date('Y-m-d H:i:s'));
});
$http->start();

test.php

<?php

use Yurun\Util\YurunHttp;
use Yurun\Util\HttpRequest;

require __DIR__ . '/vendor/autoload.php';

define('REQUEST_COUNT', 3);

go(function(){
    // Collaborative Client
    echo 'coroutine http client:', PHP_EOL, PHP_EOL;
    $time = microtime(true);
    YurunHttp::setDefaultHandler(\Yurun\Util\YurunHttp\Handler\Swoole::class); // Switch to Swoole Handler
    $channel = new \Swoole\Coroutine\Channel;
    for($i = 0; $i < REQUEST_COUNT; ++$i)
    {
        go(function() use($channel, $i){
            $http = new HttpRequest;
            $response = $http->get('http://127.0.0.1:9501/? Id='. $i); //request address
            var_dump($response->body());
            $channel->push(1);
        });
    }
    for($i = 0; $i < REQUEST_COUNT; ++$i)
    {
        $channel->pop();
    }
    $channel->close();
    echo 'coroutine http client time: ', (microtime(true) - $time) . 's', PHP_EOL, PHP_EOL;

    // curl
    echo 'curl:', PHP_EOL, PHP_EOL;
    $time = microtime(true);
    YurunHttp::setDefaultHandler(\Yurun\Util\YurunHttp\Handler\Curl::class); // Switch to Curl Handler
    $channel = new \Swoole\Coroutine\Channel;
    for($i = 0; $i < REQUEST_COUNT; ++$i)
    {
        go(function() use($channel, $i){
            $http = new HttpRequest;
            $response = $http->get('http://127.0.0.1:9501/? Id='. $i); //request address
            var_dump($response->body());
            $channel->push(1);
        });
    }
    for($i = 0; $i < REQUEST_COUNT; ++$i)
    {
        $channel->pop();
    }
    $channel->close();
    echo 'curl time: ', (microtime(true) - $time) . 's', PHP_EOL, PHP_EOL;
});

Function

First run requires composer update installation dependencies

  • Run php server.php to start the server
  • Run php test.php to start the client

Operation result

coroutine http client:

string(22) "1: 2019-09-11 08:35:54"
string(22) "0: 2019-09-11 08:35:54"
string(22) "2: 2019-09-11 08:35:54"
coroutine http client time: 1.0845630168915s

curl:

string(22) "0: 2019-09-11 08:35:55"
string(22) "1: 2019-09-11 08:35:56"
string(22) "2: 2019-09-11 08:35:57"
curl time: 3.0139901638031s

Result analysis

The above code returns the result after a second delay at the server, simulating the time-consuming of the actual business.

As can be seen from the client's time-consuming, Curl's three requests took more than three seconds in total, while the co-op client only took more than one second.

Because in the previous request, Curl waited for the time to return the content to do nothing else. While the client of the protocol waits for the content to be returned, it suspends the current protocol and then executes the code in other protocols.

Solution

Coroutine\Http\Client

Swoole's built-in protocol client implementation is suitable for developers with a certain foundation.

File: https://wiki.swoole.com/wiki/page/p-coroutine_http_client.html

Guzzle-Swoole

We may seldom write curl directly in our projects, but many third-party libraries (such as SDK for a cloud) will be useful.

These third-party libraries usually use Guzzle as the Http client, and the underlying Guzzle is implemented using Curl.

Yurun developed this scenario Guzzle-Swoole Packages are introduced to make it easy for these SDK s to support collaborations without modifying a single line of code.

Usage method

Execution command direct installation dependency: composer require yurunsoft/guzzle-swoole~1.1

Global Setting Processor:

<?php
require dirname(__DIR__) . '/vendor/autoload.php';

use GuzzleHttp\Client;
use Yurun\Util\Swoole\Guzzle\SwooleHandler;
use GuzzleHttp\DefaultHandler;

DefaultHandler::setDefaultHandler(SwooleHandler::class);

go(function(){
    $client = new Client();
    $response = $client->request('GET', 'http://www.baidu.com', [
        'verify'    =>  false,
    ]);
    var_dump($response->getStatusCode());
});

Manually specify the Swoole processor:

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use Yurun\Util\Swoole\Guzzle\SwooleHandler;

go(function(){
    $handler = new SwooleHandler();
    $stack = HandlerStack::create($handler);
    $client = new Client(['handler' => $stack]);
    $response = $client->request('GET', 'http://www.baidu.com', [
        'verify'    =>  false,
    ]);
    var_dump($response->getBody()->__toString(), $response->getHeaders());
});

YurunHttp

YurunHttp It is an open source PHP HTTP class library. It supports chain operation and is easy to use.

Support all common GET, POST, PUT, DELETE, UPDATE and other requests, support browser-level Cookies management, upload and download, set and read header, Cookie, request parameters, failure retry, speed limit, proxy, certificate and so on.

Version 3.0 perfectly supports Curl and Swoole protocols; Version 3.2 supports Swoole WebSocket clients.

Usage method

Execution command direct installation dependency: composer require yurunsoft/yurun-http~3.2

<?php
use Yurun\Util\YurunHttp;
use Yurun\Util\HttpRequest;

// Set the default request processor to Swoole
YurunHttp::setDefaultHandler(\Yurun\Util\YurunHttp\Handler\Swoole::class);

// Swoole processors must be invoked in a coroutine
go('test');

function test()
{
    $http = new HttpRequest;
    $response = $http->get('http://www.baidu.com');
    echo 'html:', PHP_EOL, $response->body();
}

By the time of publication, Swoole 4.4's new hook Curl is still an experimental feature. Although Yurun has contributed a part of the code to this function, I personally do not recommend hook Curl for the time being because of the huge workload of compatibility and too many OPTION s that are not supported.

Use Guzzle-Swoole and YurunHttp When you have any questions, you can ask me in the group (QQ group: 17916227).

Keywords: Programming curl PHP SDK JSON

Added by kr4mer on Wed, 11 Sep 2019 04:59:38 +0300