环境 linux 2核2G + php7.4

<?php

$pid = pcntl_fork();

if ($pid === 0) {
    // 连接数
    $count = $argv[2] ?: 1000;
    // 随机活跃
    $req = $argv[3] ?: 10;
    if ($req < 2) {
        throw new Exception('随机活跃数量必须大于1');
    }
    $streams = [];
    sleep(1);
    for ($i = 0; $i < $count; $i++) {
        $s = stream_socket_client(
            'tcp://127.0.0.1:8081',
            $errNo,
            $errStr
        );
        false !== $s && $streams[] = $s;
    }

    while (1) {
        foreach (array_rand($streams, $req) as $k) {
            $str = "hello.{$k}";
            fwrite($streams[$k], $str, strlen($str));
        }
    }
    exit(0);
} else {
    if (false === $server = stream_socket_server(
            'tcp://127.0.0.1:8081',
            $errNo,
            $errStr
        )
    ) {
        throw new Exception($errStr, $errNo);
    }

    $type = $argv[1] ?: 'select';

    switch ($type) {
        case 'select':
            $clients = [$server];
            $time = time();
            $msgNum = 0; // 每秒接收消息
            while (1) {
                $read = $clients;
                $write = [];
                $except = [];
                if ($count = stream_select($read, $write, $except, null)) {
                    foreach ($read as $r) {
                        if ($r === $server) {
                            $client = stream_socket_accept($r);
                            echo "select 有新连接:".(int)$client.PHP_EOL;
                            $clients[] = $client;
                        } else {
                            $data = fread($r, 1024);
                            $msgNum++;
                            $endTime = time();
                            if ($time+1 <= $endTime){
                                echo "每秒接收:" . $msgNum;
                                $time = $endTime;
                                $msgNum = 0;
                            }
//                            echo $data;
                        }
                    }
                }
            }
            break;
        case 'epoll':
            class Serve{
                private $events = [];
                private $clients = [];

                private $base;

                private $time;
                private $msgNum = 0;

                public function __construct($server) {
                    $this->base = new EventBase();
                    stream_set_blocking($server, false);
                    $this->time = time();
                    $this->events[(int)$server] = new Event(
                        $this->base,
                        $server,
                        Event::READ | Event::WRITE | Event::PERSIST,
                        function (
                            $socket
                        )
                        {
                            $client = stream_socket_accept($socket);
                            stream_set_blocking($client, false);
                            echo "epoll 有新连接:".(int)$client.PHP_EOL;
                            $this->clients[(int)$client] = $client;
                            $this->events[(int)$client] = new Event(
                                $this->base,
                                $client,
                                Event::READ | Event::WRITE | Event::PERSIST,
                                function (
                                    $fd
                                ){
                                    $data = fread($fd, 1024);
//                                    echo $data;
                                    $this->msgNum++;
                                    $endTime = time();
                                    if ($this->time+1 <= $endTime){
                                        echo "每秒接收:" . $this->msgNum ;
                                        $this->time = $endTime;
                                        $this->msgNum = 0;
                                    }
                                }
                            );
                            $this->events[(int)$client]->add();
                        }
                    );
                    $this->events[(int)$server]->add();
                }

                public function loop(){
                    $this->base->loop();
                }

            }

            (new Serve($server))->loop();
            break;
    }
}

$pid = pcntl_wait($status);

先上代码 启用2个进程 父进程服务端,子进程客户端

php index.php [select|epoll] [总连接] [活跃连接]

php index.php select 100 5

测试

QQ截图20211209143353.png
上图是cpu内存消耗,下图是每一秒打印一次接收数据量统计

在高连接低活跃情况下在epoll处理效率明显高于select,但是在高连接高活跃的情况下epoll和select效率差不多