首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP libev 擴充套件完整指南:高效能事件循環實戰

     編輯:PHP 相關知識

什麼是 libev?

libev 是一個高效能、功能完整的事件循環庫(C 語言實作),提供 epoll/kqueue/IOCP 等多平台非同步 I/O 多路複用抽象。PHP ev 擴充套件(PECL)為其提供原生介面,適用於長連線服務、即時推播、微服務閘道等高併發場景。

安裝

# Ubuntu/Debian
sudo apt-get install libev-dev
sudo pecl install ev
echo "extension=ev.so" > /etc/php/8.x/mods-available/ev.ini
sudo phpenmod ev

核心概念

  • Watcher(監視器):註冊關心的事件類型(I/O、定時、信號、子進程、閒置、準備、檢查)
  • Event Loop(事件循環):`Ev::run()` 啟動,持續輪詢並回調就緒的 Watcher
  • Reentrancy(可重入):回調中可安全建立/停止其他 Watcher

定時器實戰

<?php
// 1. 單次觸發:2 秒後執行
$w1 = new EvTimer(2, 0, function () {
    echo "2 秒後觸發一次\n";
});

// 2. 週期觸發:2 秒後首次,之後每 1 秒
$w2 = new EvTimer(2, 1, function ($w) {
    echo "每秒觸發,迭代次數:" . Ev::iteration() . "\n";
    if (Ev::iteration() >= 5) $w->stop(); // 5 次後停止
});

// 3. 建立但不啟動:稍後手動 start()
$w_stopped = EvTimer::createStopped(10, 5, function ($w) {
    echo "手動啟動的定時器\n";
    if (Ev::iteration() >= 2) $w->stop();
});

// 啟動事件循環(阻塞直到所有 watcher 停止)
Ev::run();

// 手動啟動第三個定時器,單次迭代
$w_stopped->start();
echo "單次迭代\n";
Ev::run(Ev::RUN_ONCE);

// 重啟第二個定時器,非阻塞模式
$w2->again();
Ev::run(Ev::RUN_NOWAIT);

// 新增一個長時間阻塞定時器,演示阻塞循環
$w = new EvTimer(10, 0, function() {});
echo "阻塞循環中...\n";
Ev::run();
echo "END\n";

I/O 事件實戰:非阻塞 HTTP 請求

<?php
error_reporting(E_ERROR); // 屏蔽 sockets 擴充的非阻塞警告

$eNonBlocking = [11, 115]; // EAGAIN/EWOULDBLOCK, EINPROGRESS
$port = getservbyname('www', 'tcp');
$host = 'google.com';
$ip = gethostbyname($host);

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($socket);

// 10 秒總超時監視器
$timeout = new EvTimer(10, 0, function () use ($socket) {
    socket_close($socket);
    Ev::stop(Ev::BREAK_ALL);
});

// 可寫監視器:連線成功後發送請求
$writeWatcher = new EvIo($socket, Ev::WRITE, function ($w) use ($socket, $timeout, $eNonBlocking) {
    $timeout->stop();
    $w->stop();

    $req = "HEAD / HTTP/1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";
    if (!socket_write($socket, $req, strlen($req))) {
        trigger_error("寫入失敗", E_USER_ERROR);
    }

    // 可讀監視器:接收回應
    $readWatcher = new EvIo($socket, Ev::READ, function ($w, $re) use ($socket, $eNonBlocking) {
        $ret = socket_recv($socket, $out, 20, MSG_DONTWAIT);
        if ($ret > 0) {
            echo $out;
        } elseif ($ret === 0) { // 連線關閉
            $w->stop();
            socket_close($socket);
            return;
        }
        // 非阻塞暫無資料
        if (in_array(socket_last_error(), $eNonBlocking)) return;

        $w->stop();
        socket_close($socket);
    });

    Ev::run(); // 進入子循環處理讀取
});

socket_connect($socket, $ip, $port); // 非阻塞連線,立即返回
Ev::run(); // 啟動主循環

運行模式常數

常數行為
Ev::RUN預設:阻塞直到無 watcher 或 `Ev::stop()`
Ev::RUN_ONCE單次輪詢:處理就緒事件後返回
Ev::RUN_NOWAIT非阻塞:檢查就緒事件立即返回

與 Swoole/Workerman/ReactPHP 對比

特性ext-evSwooleWorkermanReactPHP
實作層級C 擴充(最底層)C 擴充(內建 Server/Coroutine)純 PHP(stream_select)純 PHP(stream_select)
協程支援無(需自行實作)原生協程無Promise/Await
適用場景嵌入式、CLI 工具、輕量代理高併發 Server、WebSocket、微服務快速開發長連線服務元件化、框架整合

結語

libev 為 PHP 帶來了真正的非阻塞事件驅動能力。雖無內建協程,但作為底層引擎極其穩定高效。適合開發自訂協議伺服器、高效能代理、監控代理等場景。若需快速構建業務 Server,建議直接使用 Swoole 或 Workerman。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved