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.0845630168915scurl:
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