在 PHP 开发中,理解同步(Synchronous)和异步(Asynchronous)执行是构建高效应用的基石。同步执行是程序阻塞等待任务完成后再继续,而异步执行是不阻塞立即推进,结果通过回调或事件后期返回。
同步代码的核心在于:当你调用一个操作时,整个程序会暂停,直到该操作完成并返回结果。这种模式简单、直观,适合大多数业务逻辑,但在大规模并发时可能导致性能瓶颈。
考虑一个典型的数据库查询场景:
<?php
$result = Db::table('user')->where('id', 1)->select(); // 伪代码,假设查询数据库
sleep(3); // 模拟执行 3 秒
echo json_encode($result); // 只有查询完成后,才输出结果
在这里,
$result变量在select()返回前不会被赋值。程序会阻塞等待,确保数据的一致性。
另一个简单例子:数学计算
<?php
$num = -30;
$result = abs($num); // abs() 函数立即返回绝对值
echo json_encode($result); // 输出 30
abs()是同步的,调用后立即得到结果,无需等待。
在 Web 应用中,用户访问 www.tinywan.com 时,服务器会等待整个页面渲染完成再响应。这确保了响应的完整性,但如果渲染涉及耗时操作(如邮件发送),用户体验会变差。
<?php
// 模拟发送邮件
$status = sendEmail(); // 假设发送需 30 秒
sleep(30);
echo "发送邮件" . ($status ? '完成' : '失败');
这种阻塞式等待就是同步的典型表现:可靠,但效率低下。
同步的优缺点
异步代码则相反:调用操作后,程序不等待结果,而是立即继续执行后续逻辑。结果通过回调、Promise 或事件返回。这种模式适合高并发场景,能最大化资源利用。
在 PHP 中,使用 pcntl_fork() 创建子进程实现异步:
<?php
$pid = pcntl_fork();
if ($pid == 0) {
// 子进程:处理邮件发送
sleep(30); // 模拟 30 秒
sendEmail();
exit(0);
}
// 主进程不等待,继续执行
pcntl_waitpid($pid, $status, WNOHANG); // 非阻塞等待
echo "邮件发送中..."; // 立即输出
主进程启动子进程,不关心结果。这提高了响应速度,但增加了复杂性(如进程管理)。
使用 JavaScript 的 $.ajax()(PHP 可通过 Guzzle 等库模拟):
// JS 示例,PHP 类似使用 curl_multi
$.ajax({
url: '/api/data',
async: true, // 默认异步
success: function(data) {
console.log(data); // 回调处理结果
}
});
// 代码继续执行,不阻塞
console.log('继续其他任务');
异步的优缺点
传统 PHP 的同步/异步受限于多进程/线程模型,扩展性差。Swoole 扩展引入协程(Coroutine),一种用户态轻量级线程,由程序控制调度,实现“伪并行”。Swoole 进一步封装了协程工具,让异步编程像同步一样简单。
在协程中,同步不再是“阻塞线程”,而是“挂起协程”——I/O 时自动让出 CPU,避免浪费。EasySwoole 提供了 CSP(Communicating Sequential Processes)模型,使用 Channel 实现协程间通信。同时,引入 WaitGroup、Atomic 等原语,确保多协程协作安全。
为什么需要协程同步?在并发任务中(如批量数据库查询),单纯的 go() 启动子协程可能导致主协程过早结束,丢失结果。同步原语解决了“等待完成”和“数据共享”的痛点。
