本文目录导读:

在PHP项目中使用Swoole协程,主要分为以下几个步骤,我会从基础概念、环境搭建、实际代码示例到生产注意事项,给你一个完整的指南。
理解Swoole协程的核心概念
Swoole协程允许你用同步的代码写法实现异步IO的性能,关键点:
- 协程是用户态轻量级线程,创建开销极低(约2KB内存)
go()函数创建协程- 遇到IO操作(如MySQL查询、Redis读写、HTTP请求)时自动挂起,释放CPU
- IO完成后自动恢复执行
环境搭建
# 安装Swoole扩展(推荐4.8+或5.x版本) pecl install swoole # 或编译安装(更稳定) phpize && ./configure && make && make install # 验证安装 php -m | grep swoole # 必须开启协程钩子(在代码或php.ini中设置) ; php.ini 或代码中 swoole.use_shortname = 'Off' ; 可选,建议关闭短函数名
重要: Swoole 5.x及以上版本默认开启协程钩子,不需要额外设置。
基础协程示例
1 创建和运行协程
<?php
// 启用协程钩子(Swoole 4.4+)
\Swoole\Runtime::enableCoroutine();
// 创建协程
go(function () {
echo "Hello from coroutine 1\n";
// 模拟IO操作
\Swoole\Coroutine::sleep(1);
echo "After sleep in coroutine 1\n";
});
go(function () {
echo "Hello from coroutine 2\n";
\Swoole\Coroutine::sleep(0.5);
echo "After sleep in coroutine 2\n";
});
echo "Main process continues...\n";
输出:
Hello from coroutine 1
Hello from coroutine 2
Main process continues...
After sleep in coroutine 2
After sleep in coroutine 1
2 并发执行多个任务
<?php
use Swoole\Coroutine;
use function Swoole\Coroutine\run;
run(function () {
// 并发执行3个任务
$tasks = [
'task1' => function () {
Coroutine::sleep(2);
return "Task 1 result";
},
'task2' => function () {
Coroutine::sleep(1);
return "Task 2 result";
},
'task3' => function () {
Coroutine::sleep(3);
return "Task 3 result";
}
];
// 使用WaitGroup等待所有协程完成
$wg = new Coroutine\WaitGroup();
$results = [];
foreach ($tasks as $key => $task) {
$wg->add();
go(function () use ($key, $task, $wg, &$results) {
$results[$key] = $task();
$wg->done();
});
}
$wg->wait();
print_r($results);
// 总耗时约3秒(最长的那个任务),而不是6秒
});
实际项目中的典型场景
1 并发HTTP请求(替代curl_multi)
<?php
use Swoole\Coroutine\Http\Client;
use function Swoole\Coroutine\run;
run(function () {
$urls = [
'http://api.example.com/data1',
'http://api.example.com/data2',
'http://api.example.com/data3'
];
$results = [];
$wg = new \Swoole\Coroutine\WaitGroup();
foreach ($urls as $index => $url) {
$wg->add();
go(function () use ($url, $index, $wg, &$results) {
$client = new Client(parse_url($url, PHP_URL_HOST), 80);
$client->get(parse_url($url, PHP_URL_PATH));
$results[$index] = $client->body;
$client->close();
$wg->done();
});
}
$wg->wait();
print_r($results);
// 总耗时 = 最慢的请求时间(非累加)
});
2 并发数据库查询(MySQL)
<?php
use Swoole\Coroutine\MySQL;
use function Swoole\Coroutine\run;
run(function () {
// 创建连接池(生产环境请使用连接池库如easyswoole/pool)
$pool = new \Swoole\Coroutine\Channel(10);
// 初始化连接池
for ($i = 0; $i < 5; $i++) {
$db = new MySQL();
$db->connect([
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'password' => 'password',
'database' => 'test',
'charset' => 'utf8mb4',
]);
$pool->push($db);
}
// 并发执行多个查询
$queries = ['SELECT 1', 'SELECT 2', 'SELECT 3'];
$wg = new \Swoole\Coroutine\WaitGroup();
foreach ($queries as $sql) {
$wg->add();
go(function () use ($pool, $sql, $wg) {
$db = $pool->pop(); // 从池中获取连接
$result = $db->query($sql);
var_dump($result);
$pool->push($db); // 归还连接
$wg->done();
});
}
$wg->wait();
});
在现有框架中使用Swoole协程
1 结合Laravel/Lumen
// 安装swoole_laravel扩展或自己实现
composer require swooletw/laravel-swoole
// 配置文件 config/swoole_http.php
return [
'server' => [
'host' => '0.0.0.0',
'port' => 1215,
],
];
// 启动命令
php artisan swoole:http start
// 在控制器中使用协程
public function index()
{
$result = \Swoole\Coroutine\run(function () {
// 协程安全的数据库查询
$user = User::find(1); // 自动使用协程MySQL
$posts = Post::where('user_id', 1)->get();
// 并发HTTP请求
$client = new \Swoole\Coroutine\Http\Client('api.example.com', 80);
$client->get('/data');
return [
'user' => $user,
'posts' => $posts,
'api_data' => $client->body
];
});
return response()->json($result);
}
2 结合ThinkPHP
// 安装topthink/think-swoole
composer require topthink/think-swoole
// 启动
php think swoole start
// 控制器中使用
class Index
{
public function index()
{
$result = \Swoole\Coroutine\run(function () {
// 自动协程化的ORM操作
$users = User::select();
return $users;
});
return json($result);
}
}
协程安全注意事项
1 避免全局状态竞争
// ❌ 危险:全局变量在不同协程间共享
$counter = 0;
go(function () use (&$counter) {
$counter++; // 可能导致数据竞争
});
// ✅ 安全:使用Channel传递数据
$chan = new \Swoole\Coroutine\Channel();
go(function () use ($chan) {
$chan->push(1);
});
$result = $chan->pop();
2 使用协程安全的组件
// ❌ 不安全的全局单例
$db = new PDO(...); // PDO不是协程安全的
// ✅ 安全的做法:每个协程创建独立连接,或使用连接池
go(function () {
$db = new \Swoole\Coroutine\MySQL();
$db->connect([...]);
});
3 协程上下文管理
// 使用Context管理请求级别的数据
use Swoole\Coroutine\Context;
// 在协程开始处设置
$context = new Context();
$context['user_id'] = 123;
go(function () use ($context) {
// 在协程内使用
$userId = $context['user_id'];
});
生产环境部署建议
1 最佳实践配置
// 创建HTTP服务器
$http = new Swoole\Http\Server("0.0.0.0", 9501);
$http->set([
'worker_num' => swoole_cpu_num() * 2, // 根据CPU核心数设置
'max_request' => 5000, // 防止内存泄漏
'enable_coroutine' => true, // 开启协程
'hook_flags' => SWOOLE_HOOK_ALL, // 全部协程化
]);
$http->on('request', function ($request, $response) {
// 每个请求自动在协程中运行
$response->header('Content-Type', 'text/plain');
$response->end("Hello World\n");
});
$http->start();
2 部署脚本
# 启动 php server.php start # 守护进程模式 php server.php start -d # 热重启 kill -USR1 [master_pid] # 查看状态 ps aux | grep swoole
3 监控指标
// 在代码中获取协程状态 echo "当前协程数: " . \Swoole\Coroutine::stats()['coroutine_num'] . "\n"; echo "Coro总创建数: " . \Swoole\Coroutine::stats()['coroutine_peak_num'] . "\n";
常见问题排查
| 问题 | 解决方案 |
|---|---|
| 协程栈溢出 | 增加 stack_size 配置(默认2M) |
| 连接超时 | 设置 timeout 参数,添加断线重连逻辑 |
| 内存泄漏 | 检查是否所有资源都被释放,使用 max_request 限制 |
| 协程死锁 | 避免在协程间使用互斥锁,优先使用Channel |
使用Swoole协程的关键公式:
- 启用协程钩子 → 自动将同步IO转为协程IO
- 使用
go()创建任务 → 实现并发 - 使用
WaitGroup或Channel→ 同步协程结果 - 使用连接池 → 管理资源和限制并发数
- 避免全局状态共享 → 使用Channel传递数据
Swoole协程能让你在保持代码可读性的同时,获得接近Node.js的并发性能,建议从小规模功能开始尝试,逐步替换现有项目中的IO密集操作。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播