當前位置: 妍妍網 > 碼農

workerman5.0 和 swoole5.0 實作一鍵協程

2024-04-22碼農

概述

在現代的互聯網套用開發中,效能和即時性是衡量一個套用成功的關鍵指標。Workerman 和 Swoole 作為 PHP 社群中流行的高效能通訊庫,它們的結合使用為開發者提供了強大的異步網路通訊能力。本文將深入探索如何利用 Workerman 5.0 結合 Swoole 5.0 來實作一鍵協程。

🥁 問: workerman5.0 為什麽要使用 swoole5.0 ,原因很簡單: workerman5.0 全面支持Swoole驅動。更多了解:https://github.com/walkor/workerman/releases/tag/v5.0.0-beta.1

使用

強烈建議看看這個作為入門: 。

為了方便開發和部署,這裏直接使用docker容器。

docker pull tinywan/docker-php-webman:8.2.17-swoole5.1

更多使用方法可以參考這裏 https://github.com/Tinywan/docker-php-webman。該容器支持 swoole 擴充套件 5.1.1

# pecl info swoole
About pecl.php.net/swoole-5.1.1
===============================
Release Type PECL- style PHP extension (source code)
Name swoole
Channel pecl.php.net
Summary Event-driven asynchronous and concurrent
networking engine with high performance for PHP.
Description Event-driven asynchronous and concurrent
networking engine with high performance for PHP.
- event-driven
- coroutine
- asynchronous non-blocking
- multi-thread reactor
- multi-process worker
- multi-protocol
- millisecond timer
- built-in tcp/http/websocket/http2 server
- coroutine tcp/http/websocket client
- coroutine mysql client
- coroutine redis client
- coroutine read/write file system
- coroutine dns lookup
- support IPv4/IPv6/UnixSocket/TCP/UDP
- support SSL/TLS encrypted transmission
Maintainers Tianfeng Han <rango@swoole.com> (lead)
Twosee <twosee@php.net> (developer)
Shen Zhe <shenzhe163@gmail.com> (developer,
inactive)
Lu Fei <lufei@php.net> (developer)
Bruce Dou <doubaokun@php.net> (developer)
Release Date2023-11-2614:25:25
Release Version 5.1.1 (stable)
API Version 5.0 (stable)
License Apache2.0
(http://www.apache.org/licenses/LICENSE-2.0.html)
Release Notes - Fixed memory leak issue in HTTP coroutine
client
- Fixed the issue of can not hook pdo_odbc
- Fixed the error in executing
socket_import_stream()
- Fixed the issue with
Context::parse_multipart_data() unable to handle
empty request body
- Fixed the issue with PostgreSQL coroutine
client where the parameters are not working
- Fixed the bug where curl crashes during
destruction
- Fixed the compatibility issue between Swoole
5.x and the latest version of xdebug
- Fixed the problem of  class not found error
caused by coroutine switching during the process
of  class autoloading
- Fixed the issue of not being able to compile
Swoole on OpenBSD
Required Dependencies PHP version 8.0.0
PEAR installer version 1.4.0 or newer
package.xml version 2.0
Last Modified 2024-04-2110:05
Previous Installed - None -
Version

開啟swoole事件驅動

webman 框架中開啟 swoole 事件驅動特別簡單,只有配置一下就可以了。修改配置檔 config/server.php 服務配置檔

'event_loop' => Workerman\Events\Swoole:: class

Docker 啟動webman

$ docker run --rm -it -p 8887:8787 -v d:/dnmp/www/webman2024:/app tinywan/docker-php-webman:8.2.17-swoole5.1
2024-04-2114:13:53,255 INFO Set uid to user 0 succeeded
2024-04-2114:13:53,266 INFO supervisord started with pid 1
2024-04-2114:13:54,272 INFO spawned: 'webman'with pid 7
Workerman[/app/start.php] start in DEBUG mode
-------------------------------------------------- WORKERMAN --------------------------------------------------
Workerman version:5.0.0 PHP version:8.2.17 Event-loop:Workerman\Events\Swoole
--------------------------------------------------- WORKERS ---------------------------------------------------
proto user worker listen processes state
tcp root webman http://0.0.0.0:8787 8 [OK]
tcp root monitor none 1 [OK]
tcp root push_chart none 1 [OK]
tcp root plugin.webman.push.server websocket://0.0.0.0:8788 1 [OK]
---------------------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.

swoole實作協程

協程虛擬碼

<?php
/**
 * @desc Swoole 協程入門
 * @author Tinywan(ShaoBo Wan)
 * @date 2024/4/22 19:27
 */

declare(strict_types=1);
functiontask1(){
for ($i=0;$i<=5;$i++){
//寫入檔,大概要3000微秒
usleep(3000);
echo'[x] [寫入檔] ['.$i.'] ' . date('Y-m-d H:i:s') . PHP_EOL;
\Co::sleep(0.001);//掛起當前協程,0.001秒後恢復//相當於切換協程
}
}
functiontask2(){
for ($i=0;$i<=10;$i++){
//發送信件給500名會員,大概3000微秒
usleep(3000);
echo'[x] [發送信件] ['.$i.'] ' . date('Y-m-d H:i:s') . PHP_EOL;
Co::sleep(0.001);//掛起當前協程,0.001秒後恢復//相當於切換協程
}
}
functiontask3(){
for ($i=0;$i<=15;$i++){
//模擬插入100條數據,大概3000微秒
usleep(3000);
echo'[x] [插入數據] ['.$i.'] ' . date('Y-m-d H:i:s') . PHP_EOL;
Co::sleep(0.001);//掛起當前協程,0.001秒後恢復//相當於切換協程
}
}
$pid1 = go('task1'); //go函式是swoole的開啟協程函式,用於開啟一個協程
$pid2 = go('task2');
$pid3 = go('task3');

執行結果

[x] [寫入檔] [02024-04-2113:31:37
[x] [發送信件] [02024-04-2113:31:37
[x] [插入數據] [02024-04-2113:31:37
[x] [寫入檔] [12024-04-2113:31:37
[x] [發送信件] [12024-04-2113:31:37
[x] [插入數據] [12024-04-2113:31:37
[x] [寫入檔] [22024-04-2113:31:37
[x] [發送信件] [22024-04-2113:31:37
[x] [插入數據] [22024-04-2113:31:37
[x] [寫入檔] [32024-04-2113:31:37
[x] [發送信件] [32024-04-2113:31:37
[x] [插入數據] [32024-04-2113:31:37
[x] [寫入檔] [42024-04-2113:31:37
[x] [發送信件] [42024-04-2113:31:37
[x] [插入數據] [42024-04-2113:31:37
[x] [寫入檔] [52024-04-2113:31:37
[x] [發送信件] [52024-04-2113:31:37
[x] [插入數據] [52024-04-2113:31:37
[x] [發送信件] [62024-04-2113:31:37
[x] [插入數據] [62024-04-2113:31:37
[x] [發送信件] [72024-04-2113:31:37
[x] [插入數據] [72024-04-2113:31:37
[x] [發送信件] [82024-04-2113:31:37
[x] [插入數據] [82024-04-2113:31:37
[x] [發送信件] [92024-04-2113:31:37
[x] [插入數據] [92024-04-2113:31:37
[x] [發送信件] [102024-04-2113:31:37
[x] [插入數據] [102024-04-2113:31:37
[x] [插入數據] [112024-04-2113:31:37
[x] [插入數據] [122024-04-2113:31:37
[x] [插入數據] [132024-04-2113:31:37
[x] [插入數據] [142024-04-2113:31:37
[x] [插入數據] [152024-04-2113:31:37

為什麽要用 sleep 掛起協程實作切換呢?因為swoole的協程是自動的,當協程內遇上 I/O 操作(mysql,redis)等時,swoole的協程會自動切換,執行到下一個協程任務中(切換後,I/O繼續執行),直到下一個協程任務完成或者被切換(遇上I/O),如此反復,直到所有協程任務完成,則任務完成。

MySQL 一鍵協程化

<?php
usefunctionSwoole\Coroutine\run;
usefunctionSwoole\Coroutine\go;
run(function(){
go(function(){
$pdo = new \PDO('mysql:host=192.168.3.29;port=3308;dbname=nacos;charset=utf8''root''123456');
$statement = $pdo->prepare('SELECT * FROM `users`');
$statement->execute();
var_dump($statement->fetchAll());
});
go(function(){
$mysqli = new mysqli('192.168.3.29''root''123456''webman-admin'3308);
$mysqli->set_charset('utf8mb4');
var_dump($mysqli);
});
});

執行結果

array(1) {
[0]=>
array(6) {
["username"]=>
string(5) "nacos"
[0]=>
string(5) "nacos"
["password"]=>
string(60) "$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu"
[1]=>
string(60) "$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu"
["enabled"]=>
int(1)
[2]=>
int(1)
}
}
object(mysqli)#6 (18) {
["affected_rows"]=>
int(0)
["client_info"]=>
string(14) "mysqlnd 8.2.17"
["client_version"]=>
int(80217)
["connect_errno"]=>
int(0)
["connect_error"]=>
NULL
["errno"]=>
int(0)
["error"]=>
string(0) ""
["error_list"]=>
array(0) {
}
["field_count"]=>
int(0)
["host_info"]=>
string(23) "192.168.3.29 via TCP/IP"
["info"]=>
NULL
["insert_id"]=>
int(0)
["server_info"]=>
string(6) "5.7.36"
["server_version"]=>
int(50736)
["sqlstate"]=>
string(5) "00000"
["protocol_version"]=>
int(10)
["thread_id"]=>
int(104)
["warning_count"]=>
int(0)
}

致謝: 感謝 Workerman 和 Swoole 開發團隊為 PHP 社群帶來的創新和卓越貢獻,讓我們共同期待 PHP 在即時套用領域的更多突破。

參考

  • https://www.easyswoole.com/NoobCourse/coroutine.html

  • https://wiki.swoole.com/#/runtime