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

PHP Session 讀寫鎖機制實證:長耗時請求阻塞並發的解決方案

     編輯:PHP 綜合知識

現象重現

頁面 A 執行耗時 10 秒的 PHP 腳本並寫入 Session 進度;頁面 B 輪詢讀取 Session 顯示進度。預期每秒更新,實際 **10 秒後一次性顯示 complete**。

根本原因

PHP 預設 Session 處理器 (files) 以 **獨佔鎖** 開啟 Session 檔案:

  1. session_start() → flock(LOCK_EX) 獲取寫鎖。
  2. 腳本執行期間 **持有鎖**,其他請求同 Session ID 呼叫 session_start() 會 **阻塞等待鎖釋放**。
  3. 腳本結束或 session_write_close() → 釋放鎖。

代碼重現

<!-- session.html -->
<button onclick="handle()">開始</button>
<div id="result"></div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
function handle() {
    $.get("handle.php"); // 觸發長任務
    setInterval(() => $.get("getstep.php").done(d => {
        $('#result').html('步驟: ' + d);
        if (d === 'complete') clearInterval(timer);
    }), 500);
}
</script>

<?php // handle.php
session_start();
for ($i=1; $i<=10; $i++) {
    $_SESSION['step'] = $i;
    sleep(1);
}
$_SESSION['step'] = 'complete';
?>

<?php // getstep.php
session_start();
echo $_SESSION['step'] ?? '';
?>

解決方案對比

方案原理優點缺點
session_write_close()提前寫入並釋放鎖,後續邏輯不再寫 Session零依賴、即時生效後續無法寫入 Session
Redis/Memcached Session分散式 Session,通常無全域鎖或鎖粒度更細高併發、支援叢集需額外基礎設施
session.save_handler = user自定義讀寫鎖邏輯 (如樂觀鎖、行級鎖)完全可控開發複雜度高
異步任務隊列長任務放入隊列,前端輪詢任務狀態 (不依賴 Session)架構正交、擴展性最佳引入隊列基礎設施

最佳實踐:session_write_close() 範例

<?php // handle.php 優化版
session_start();
$_SESSION['step'] = 0;
session_write_close(); // 釋放鎖!

for ($i=1; $i<=10; $i++) {
    // 需更新進度時,重新開啟、寫入、關閉 (極短暫持有鎖)
    session_start();
    $_SESSION['step'] = $i;
    session_write_close();
    sleep(1);
}
session_start();
$_SESSION['step'] = 'complete';
session_write_close();

結語

PHP Session 檔案鎖是隱形效能殺手。長耗時請求 **務必** 在進入耗時邏輯前呼叫 session_write_close(),或將進度寫入 Redis/資料庫/暫存檔,避免阻塞同用戶其他請求。架構層面採用異步任務隊列徹底解耦,是高併發系統的標準解法。

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