PHP 怎么Runtime 协程

wen PHP项目 1

本文目录导读:

PHP 怎么Runtime 协程

  1. 使用 Swoole 扩展(最常用)
  2. 使用 Fiber(PHP 8.1+ 原生)
  3. 并发协程管理
  4. 协程池实现
  5. 协程之间通信
  6. 实际的 HTTP 请求示例
  7. 协程超时控制
  8. 注意事项

在 PHP 中实现运行时协程,主要有以下几种方式:

使用 Swoole 扩展(最常用)

<?php
// Swoole 协程示例
use Swoole\Coroutine;
// 创建协程
Coroutine::create(function () {
    echo "协程1开始\n";
    // 模拟IO操作
    Coroutine::sleep(1);
    echo "协程1结束\n";
});
Coroutine::create(function () {
    echo "协程2开始\n";
    Coroutine::sleep(0.5);
    echo "协程2结束\n";
});
echo "主程序继续运行\n";
// 等待所有协程完成
Swoole\Coroutine\run();
?>

使用 Fiber(PHP 8.1+ 原生)

<?php
// PHP 8.1+ 原生 Fiber 示例
$fiber = new Fiber(function() {
    echo "Fiber开始\n";
    // 暂停执行,返回给调用者
    $value = Fiber::suspend('暂停中');
    echo "收到值: $value\n";
    echo "Fiber结束\n";
    return "Fiber返回值";
});
// 启动 Fiber
$result = $fiber->start();
echo "主程序: $result\n";
// 恢复 Fiber 执行
$result = $fiber->resume('继续执行');
echo "主程序: $result\n";
?>

并发协程管理

<?php
// 并发执行多个协程
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
$channel = new Channel(10);
// 创建多个任务
$tasks = [
    'task1' => function() {
        Coroutine::sleep(1);
        return '任务1结果';
    },
    'task2' => function() {
        Coroutine::sleep(0.5);
        return '任务2结果';
    },
    'task3' => function() {
        Coroutine::sleep(2);
        return '任务3结果';
    }
];
// 并发执行所有任务
$results = Coroutine\parallel($tasks);
print_r($results);
?>

协程池实现

<?php
class CoroutinePool {
    private array $coroutines = [];
    private int $maxConcurrency;
    public function __construct(int $maxConcurrency) {
        $this->maxConcurrency = $maxConcurrency;
    }
    public function submit(callable $task, ...$args): void {
        $this->coroutines[] = [
            'task' => $task,
            'args' => $args
        ];
    }
    public function execute(): array {
        $results = [];
        // 分批执行
        $batches = array_chunk($this->coroutines, $this->maxConcurrency);
        foreach ($batches as $batch) {
            foreach ($batch as $coroutine) {
                $results[] = call_user_func_array($coroutine['task'], $coroutine['args']);
            }
        }
        return $results;
    }
}
// 使用示例
$pool = new CoroutinePool(3);
$pool->submit(function($data) {
    usleep(100000); // 模拟IO
    return "处理: $data";
}, '数据1');
$pool->submit(function($data) {
    usleep(100000);
    return "处理: $data";
}, '数据2');
$results = $pool->execute();
print_r($results);
?>

协程之间通信

<?php
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
$channel = new Channel();
// 生产者协程
Coroutine::create(function() use ($channel) {
    for ($i = 0; $i < 5; $i++) {
        echo "生产: $i\n";
        $channel->push($i);
        Coroutine::sleep(0.1);
    }
});
// 消费者协程
Coroutine::create(function() use ($channel) {
    while (true) {
        $data = $channel->pop();
        if ($data === false) break;
        echo "消费: $data\n";
        Coroutine::sleep(0.2);
    }
});
Coroutine\run();
?>

实际的 HTTP 请求示例

<?php
// 使用 Swoole 实现并发 HTTP 请求
use Swoole\Coroutine\Http\Client;
use Swoole\Coroutine;
$urls = [
    'https://api.example.com/user/1',
    'https://api.example.com/user/2',
    'https://api.example.com/user/3',
];
$requests = [];
foreach ($urls as $url) {
    $requests[] = Coroutine::create(function() use ($url) {
        $client = new Client('api.example.com', 443, true);
        $client->get('/user/1');
        return $client->body;
    });
}
// 等待所有请求完成
Coroutine\run();
echo "所有请求完成\n";
?>

协程超时控制

<?php
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
function withTimeout(callable $task, float $timeout) {
    $channel = new Channel(1);
    // 启动任务协程
    Coroutine::create(function() use ($task, $channel) {
        try {
            $result = $task();
            $channel->push(['success' => true, 'data' => $result]);
        } catch (\Exception $e) {
            $channel->push(['success' => false, 'error' => $e->getMessage()]);
        }
    });
    // 等待结果或超时
    $result = $channel->pop($timeout);
    if ($result === false) {
        return ['success' => false, 'error' => '超时'];
    }
    return $result;
}
// 使用示例
$result = withTimeout(function() {
    Coroutine::sleep(2);
    return '任务完成';
}, 1.5);
var_dump($result);
?>

注意事项

  1. 协程不是线程:PHP 的协程是单线程的,不能利用多核 CPU
  2. 阻塞操作:避免在协程中使用阻塞操作(如 sleep、file_get_contents),应使用协程版本
  3. 内存管理:协程会占用内存,需要注意控制协程数量
  4. 异常处理:协程中的异常需要通过 try-catch 捕获

选择哪种方案取决于你的 PHP 版本和环境需求,如果是 PHP 8.1+,可以使用原生的 Fiber;如果需要更强大的功能,建议使用 Swoole 扩展。

抱歉,评论功能暂时关闭!