A detailed analysis of the solution of Curl in Swoole cooperation

  • 2021-12-21 04:17:27
  • OfStack

Preface

As we all know, in Swoole applications, Curl is not recommended because Curl blocks processes.

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

Finally, the solution of Curl in Swoole will be given. If you don't want to see the analysis, you can pull it directly to the end.

Routine comparison

Yu Run do not like those virtual articles, so their own writing is more real, run 1 code directly, and use data to see why not recommend Swoole to use Curl.

In order to be lazy, I directly used Curl and Swoole and Handler of YurunHttp instead of those smelly and long Curl codes.

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); //  Assume that various processes take time 1 Seconds 
  $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(){
  //  Synergetic 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;
});

Run

First run requires composer update installation dependency

Run php server. php to start the server

Run php test. php to start the client

Running 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 the server delays for 1 second, simulating the time spent in actual business.

It can be seen from the time spent on the client that the three requests of Curl took more than 3 seconds in total, while the collaborative client only took more than 1 second.

Because in the previous request, Curl waited for the content to return for nothing else. While the program client waits to return content, it suspends the current program and executes the code in other programs instead.

Solutions

CoroutineHttpClient

Use Swoole built-in co-process client implementation, suitable for developers with a fixed foundation.

Document: https://wiki.swoole.com/wiki/...

Guzzle-Swoole

We may rarely write curl directly in the project, but many third-party class libraries used (such as SDK of so-and-so clouds) will be useful.

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

Yurun has developed Guzzle-Swoole packages for this scenario. After introduction, these SDK can easily support collaborative processes without modifying one line of code.

Usage

Execute the command to install dependencies directly: 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 is an open source PHP HTTP class library that supports chain operation and is easy to use.

Support all common request modes such as GET, POST, PUT, DELETE, UPDATE, etc. Support browser-level Cookies management, upload and download, set and read header, Cookie, request parameters, failed retry, speed limit, agent, certificate, etc.

Version 3.0 perfectly supports Curl and Swoole cooperation; Version 3.2 supports the Swoole WebSocket client.

Usage

Execute the command to install dependencies directly: composer require yurunsoft/yurun-http ~3.2


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

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

// Swoole  The processor must be called in the co-process 
go('test');

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

As of press time, the new hook Curl in Swoole 4.4 is still an experimental function. Although Yurun has contributed 1 part of the code to this function, due to the heavy workload of compatibility, too many OPTION are not supported, so I personally do not recommend using hook Curl for the time being.

Summarize


Related articles: