Swoole 协程运行时

定位

Swoole 不是框架,是 PHP 扩展。 它给 PHP 加上协程、常驻内存、异步 IO 的能力,但不提供路由、ORM、模板。

装好 Swoole 之后,你依然需要框架——Hyperf 之所以能跑协程,是因为 Swoole 提供了底层运行时。

把这点搞清楚,后面所有讨论才成立。

安装

# 方式一:pecl
pecl install swoole

1. 方式二:源码编译(需要定制编译选项时)
wget https://github.com/swoole/swoole-src/archive/refs/tags/v6.0.0.tar.gz
tar -xzf v6.0.0.tar.gz && cd swoole-src-6.0.0
phpize && ./configure --enable-openssl --enable-http2 --enable-swoole-curl
make -j && sudo make install

php.ini 里启用:

extension=swoole.so

验证:

php -m | grep swoole
php --ri swoole      # 看编译选项

核心概念

1. 协程:用同步写法做异步

<?php
// 传统阻塞写法,三个请求串行,总耗时 = 1 + 2 + 3 = 6 秒
$a = file_get_contents('https://api.a.com');   // 阻塞
$b = file_get_contents('https://api.b.com');

// 协程写法,用 Swoole 的协程客户端
use SwooleCoroutine;
use function SwooleCoroutinerun;

run(function () {
    $results = [];
    // 并发发起三个请求,总耗时约等于最慢的那个
    Coroutineparallel(3, function ($i) use (&$results) {
        $cli = new CoroutineHttpClient('api.example.com', 443, true);
        $cli->get('/');
        $results[$i] = $cli->body;
    });
});

关键:协程不是并行计算,是「IO 时让出 CPU」。所以它只对 IO 密集场景有效(网络请求、数据库、文件)。

2. 必须用协程化的客户端

这是最重要的一条。 普通 PHP 函数是阻塞的,在协程里调用会堵死整个进程:

用途阻塞(不能用)协程化(要用)
HTTPcurl、file_get_contentsSwooleCoroutineHttpClient
MySQLPDO、mysqliSwooleCoroutineMySQL
Redisredis 扩展SwooleCoroutineRedis
文件file_get_contentsSwooleCoroutineSystem::readFile

一个 file_get_contents 就能让整个服务的并发能力掉到个位数,而且不报错。

Swoole 提供了一键协程化的方案:

; php.ini 里开启运行时钩子
swoole.enable_library=php_stream
swoole.enable_coroutine=true

开了钩子后,PDO、curl、file_get_contents 会被自动替换成协程版本。这是最容易落地的方案,但要注意兼容性。

3. 常驻内存:全局状态会残留

// 危险:这个静态数组会在所有请求间共享
class Cache
{
    public static array $data = [];
}

在 FPM 里每次请求都是新进程,静态变量清空。在 Swoole 常驻进程里,它会一直累积。

解决办法:用 SwooleCoroutine::getContext() 存请求级数据:

use SwooleCoroutine;

Coroutine::getContext()['user_id'] = $id;    // 只属于当前协程

4. 两种运行模式

模式用法适合
协程容器Coroutinerun(fn() => ...)脚本、CLI、和现有 FPM 项目混用
常驻 ServerSwooleHttpServer 等完整的高性能服务

常见坑

① 编译选项不全

--enable-openssl、--enable-http2、--enable-swoole-curl 这些编译选项决定了能力。用 pecl 默认编译可能缺功能,后期改要重新编译。

② 协程内不能用 sleep

sleep() 会阻塞整个进程。要用 SwooleCoroutine::sleep()。

③ 超全局变量不可靠

$_GET、$_POST、$_SERVER 在协程间会串。必须用 Swoole 提供的请求对象。

④ 版本差异大

4.x 和 5.x 的协程实现有变化(5.x 后更稳定),6.x 又加入了新的特性。教程版本要先确认。

什么时候用它

直接装 Swoole 的合理场景:

  • 用 Hyperf(它依赖 Swoole)
  • 需要写常驻进程但不想引入 Workerman
  • 现有项目想给某几个接口加速(用协程容器包一层)

不合适:想「装个扩展就让网站变快」。网站变快靠的是减少数据库查询、加缓存,不是换运行时。

一个务实的路径

如果你的目标是「让 PHP 服务更快」,建议的顺序是:

  1. 先加 OPcache(几行配置,立竿见影)
  2. 再做对象缓存(Redis 缓存热点查询)
  3. 然后 profile,找到真正的瓶颈
  4. 最后才考虑协程(如果瓶颈确实在「每请求初始化」)

跳过前三步直接上 Swoole,通常得到的是「更快的错误」——因为业务逻辑和查询没优化,协程只是让同样的查询跑得更快一点。

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇