laitimes

workerman5.0 异步非阻塞HTTP协程客户端

author:Not bald programmer
workerman5.0 异步非阻塞HTTP协程客户端

overview

The Asynchronous HTTP Coroutine Client component in Workerman 5.0 is a high-performance HTTP client based on PHP coroutines that takes full advantage of PHP's asynchronous features to improve the efficiency and performance of HTTP requests. This component allows developers to write PHP code in a synchronous manner to send asynchronous HTTP requests, making the code more concise and easy to understand, while also being able to handle a large number of concurrent requests.

Features of this component include:
  • Asynchronous non-blocking: All requests and responses are made asynchronously and do not block the main thread, which means that multiple HTTP requests and responses can be processed at the same time.
  • Built-in connection pooling: To improve efficiency and performance, this component has a built-in connection pool, which can reuse TCP connections and reduce the overhead of establishing and closing connections.
  • PSR-7 Compliant: Both message requests and responses are PSR-7 compliant, which allows it to integrate seamlessly with other PHP components and libraries that follow the specification.
  • Supports multiple protocols: In addition to HTTP and HTTPS, the component also supports protocols such as WebSocket and WSS, enabling it to cope with more application scenarios.

Installation

Note: 5.0 requires PHP version greater than 8.2.4 or later

Use php -v to view your current PHP version information

php -v
PHP 8.2.18 (cli) (built: Apr 11 2024 19:20:54) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.18, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.18, Copyright (c), by Zend Technologies           

workerman 5.0 installation

composer require workerman/workerman v5.0.0-beta.7           
workerman5.0 异步非阻塞HTTP协程客户端

revolt/event-loop installation

What is Revolt?

Revolt is a rock-solid event loop for concurrent PHP applications. The usual PHP application spends most of its time waiting for I/O. While PHP is single-threaded, collaborative multitasking can be used to allow for concurrency by using wait times to do different things.

PHP's traditional synchronous execution process is easy to understand. Do one thing at a time. If you query the database, the query is sent and waits for a response from the database server. Once you have the answer, you can move on to the next thing.

ReactPHP and other libraries have been providing collaborative multitasking in PHP for a long time. However, their event-driven nature is incompatible with many existing interfaces and requires a different mindset. PHP 8.1 comes with built-in fibers, which provides collaborative multithreading. Calls can be asynchronous with no promises or callbacks, while still allowing non-blocking I/O.

Every application that uses collaborative multitasking needs a scheduler (also known as an event loop), and this package provides it. Revolt is the result of years of experience combining React and ReactPHP's event loop implementations. However, it is not a full-fledged framework for writing concurrent PHP applications, but rather provides the necessary public foundation. Different (strongly) opinionated libraries can be built on top of it, and React and ReactPHP will continue to coexist.

Revolt Support Events
  • The defer callback is executed on the next iteration of the event loop. If there is a delayed schedule, the event loop does not wait between iterations.
  • Delay executes the callback after a specified number of seconds. The fraction of a second can be expressed as a floating-point number.
  • Repeat executes the callback repeatedly after a specified number of seconds. The fraction of a second can be expressed as a floating-point number.
  • Stream readable callbacks are executed when there is data on the stream to read or when the connection is closed.
  • Stream writable executes a callback when there is enough space in the write buffer to accept new data to be written.
  • Signal executes a callback when a process receives a specific signal from the operating system.
Installation
composer require revolt/event-loop           
workerman5.0 异步非阻塞HTTP协程客户端

workerman/http-client installation

workerman/http-client is an asynchronous http client component. All request responses are asynchronous and non-blocking, with built-in connection pooling, and message requests and responses are PSR7 compliant. Learn more: https://www.workerman.net/doc/workerman/components/workerman-http-client.html
composer require workerman/http-client           
workerman5.0 异步非阻塞HTTP协程客户端

Write code

http.php pseudocode

<?php
/**
 * @desc 伪代码
 * @author Tinywan(ShaoBo Wan)
 * @date 2024/11/14 15:14
 */
declare(strict_types=1);

use Workerman\Worker;

require_once '../vendor/autoload.php';

try {
    $worker = new Worker();
    $worker->onWorkerStart = function () {
        $http = new Workerman\Http\Client();

        $response = $http->get('https://www.tinywan.com/');
        var_dump($response->getStatusCode());
        echo $response->getBody() . PHP_EOL;

        $response = $http->post('https://www.tinywan.com/', ['key1' => 'value1', 'key2' => 'value2']);
        var_dump($response->getStatusCode());
        echo $response->getBody() . PHP_EOL;

        $response = $http->request('https://www.tinywan.com/', [
            'method' => 'GET',
            'version' => '1.1',
            'headers' => ['Connection' => 'keep-alive'],
            'data' => ['key1' => 'value1', 'key2' => 'value2'],
        ]);
        echo $response->getBody() . PHP_EOL;
    };
    Worker::runAll();
} catch (Throwable $throwable) {
    var_dump($throwable->getMessage());
}           

Start the service

/var/www/workerman5.x-demo/coroutine # php http.php start
Workerman[http.php] start in USER mode
---------------------------------------- WORKERMAN -----------------------------------------
Workerman version:5.0.0-beta.7    PHP version:8.2.18     Event-loop:Workerman\Events\Revolt
----------------------------------------- WORKERS ------------------------------------------
proto   user            worker          listen          processes    state            
tcp     root            none            none            1             [OK]            
--------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.           
Note: Event-loop is used here: Workerman\Events\Revolt event

Execution result

int(200)
int(405)
int(200)
           

http-client 协程异步并发

<?php
/**
 * @desc 伪代码
 * @author Tinywan(ShaoBo Wan)
 * @date 2024/11/14 15:14
 */
declare(strict_types=1);

use Workerman\Worker;
use \Workerman\Connection\TcpConnection;
use \Workerman\Protocols\Http\Request;

require_once '../vendor/autoload.php';

// 创建一个Worker监听8217端口,使用http协议通讯
$httpWorker = new Worker("http://0.0.0.0:8217");

// 启动8个进程对外提供服务
$httpWorker->count = 8;

// 接收到浏览器发送的数据时回复给浏览器
$httpWorker->onMessage = function (TcpConnection $connection, Request $request) {
    $http = new \Workerman\Http\Client();

    $count = 50;
    $result = [];
    while ($count--) {
        $startTime = microtime(true);
        echo '开始时间:' . $startTime . PHP_EOL;
        $response = $http->get('https://api.tinywan.com/systems/website');
        $endTime = microtime(true);
        echo '结束时间:' . $endTime . PHP_EOL;
        $result[] = sprintf('第%d个 | 耗时%s秒 | 状态码%d', $count, $endTime - $startTime, $response->getStatusCode());
    }
    $connection->send(json_encode($result));
};

// 运行worker
Worker::runAll();           

Execution result (to be continued...... )

[
    "第49个 | 耗时0.53055596351624秒 | 状态码200",
    "第48个 | 耗时0.11245107650757秒 | 状态码200",
    "第47个 | 耗时0.13903284072876秒 | 状态码200",
    "第46个 | 耗时0.21533107757568秒 | 状态码200",
    "第45个 | 耗时0.11252999305725秒 | 状态码200",
    "第44个 | 耗时0.15401482582092秒 | 状态码200",
    "第43个 | 耗时0.10678505897522秒 | 状态码200",
    "第42个 | 耗时0.099571943283081秒 | 状态码200",
    "第41个 | 耗时0.12561202049255秒 | 状态码200",
    "第40个 | 耗时0.10563802719116秒 | 状态码200",
    "第39个 | 耗时0.11354088783264秒 | 状态码200",
    "第38个 | 耗时0.1011688709259秒 | 状态码200",
    "第37个 | 耗时0.20793986320496秒 | 状态码200",
    "第36个 | 耗时0.1089551448822秒 | 状态码200",
    "第35个 | 耗时0.092885971069336秒 | 状态码200",
    "第34个 | 耗时0.10161209106445秒 | 状态码200",
    "第33个 | 耗时0.20717096328735秒 | 状态码200",
    "第32个 | 耗时0.20546984672546秒 | 状态码200",
    "第31个 | 耗时0.11044192314148秒 | 状态码200",
    "第30个 | 耗时0.12123489379883秒 | 状态码200",
    "第29个 | 耗时0.11858606338501秒 | 状态码200",
    "第28个 | 耗时0.17020511627197秒 | 状态码200",
    "第27个 | 耗时0.095601081848145秒 | 状态码200",
    "第26个 | 耗时0.11254286766052秒 | 状态码200",
    "第25个 | 耗时0.19883704185486秒 | 状态码200",
    "第24个 | 耗时0.20402407646179秒 | 状态码200",
    "第23个 | 耗时0.10713791847229秒 | 状态码200",
    "第22个 | 耗时0.11914396286011秒 | 状态码200",
    "第21个 | 耗时0.094994068145752秒 | 状态码200",
    "第20个 | 耗时0.10224294662476秒 | 状态码200",
    "第19个 | 耗时0.11380887031555秒 | 状态码200",
    "第18个 | 耗时0.10260701179504秒 | 状态码200",
    "第17个 | 耗时0.28102612495422秒 | 状态码200",
    "第16个 | 耗时0.10411977767944秒 | 状态码200",
    "第15个 | 耗时0.10007786750793秒 | 状态码200",
    "第14个 | 耗时0.095911979675293秒 | 状态码200",
    "第13个 | 耗时0.094711065292358秒 | 状态码200",
    "第12个 | 耗时0.09196400642395秒 | 状态码200",
    "第11个 | 耗时0.10585021972656秒 | 状态码200",
    "第10个 | 耗时0.092756032943726秒 | 状态码200",
    "第9个 | 耗时0.23688101768494秒 | 状态码200",
    "第8个 | 耗时0.20317101478577秒 | 状态码200",
    "第7个 | 耗时0.10062909126282秒 | 状态码200",
    "第6个 | 耗时0.20747685432434秒 | 状态码200",
    "第5个 | 耗时0.11253881454468秒 | 状态码200",
    "第4个 | 耗时0.12536215782166秒 | 状态码200",
    "第3个 | 耗时0.17252016067505秒 | 状态码200",
    "第2个 | 耗时0.12250709533691秒 | 状态码200",
    "第1个 | 耗时0.10875701904297秒 | 状态码200",
    "第0个 | 耗时0.10053586959839秒 | 状态码200"
]           
Warehouse address: https://github.com/Tinywan/workerman5.x-demo