91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP怎么實現平滑關閉和重啟

發布時間:2022-05-19 14:36:03 來源:億速云 閱讀:157 作者:iii 欄目:開發技術

本篇內容介紹了“PHP怎么實現平滑關閉和重啟”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

原理

要實現平滑關閉/重啟不難,這里先講解兩個知識點:

阻塞信號

當我們的程序正在處理一個任務的時候,你肯定不希望它中途被終止,比如說你在執行一個數據庫事務,肯定不希望事務還沒被提交進程就被終止了。

<?php
echo "開始執行事務" . PHP_EOL;
// 模擬一些耗時的操作
$finish_time = time() + 5;
while (time() < $finish_time) {
}
echo "事務執行完畢" . PHP_EOL;

上面這段代碼,如果你在第二個 echo 之前用 kill 命令去殺死這個進程,那么第二個 echo 就不會被執行了。那能不能做到在事務過程中暫時先忽略 kill 信號呢?

能。我們可以使用 pcntl_sigprocmask() 來阻塞信號,讓事務完成之后再響應 kill 信號。

<?php

// 阻塞信號
$sig_set = array(SIGINT, SIGTERM); // 要阻塞的信號集合
pcntl_sigprocmask(SIG_BLOCK, $sig_set); // SIG_BLOCK: 把信號加入到當前阻塞信號中

echo date("[Y-m-d H:i:s]") . " 開始執行事務" . PHP_EOL;

$finish_time = time() + 5;
while (time() < $finish_time) {
}

echo date("[Y-m-d H:i:s]") . "事務執行完畢" . PHP_EOL;

pcntl_sigprocmask(SIG_UNBLOCK, $sig_set); // SIG_UNBLOCK: 從當前阻塞信號中移出信號

同樣的,在第二個 echo 之前按下 Ctrl + C 或者用 kill 命令去殺這個進程,你會發現第二個 echo 正常執行了,并且兩條輸出的時間間隔是 5 秒。

我們的常駐進程通常是在一個 while(true) 循環中去執行重復的任務,如果這么寫的話:

<?php
while (true) {
    pcntl_sigprocmask(SIG_BLOCK, $sig_set);
    // ...
    pcntl_sigprocmask(SIG_UNBLOCK, $sig_set);
}

我們是可以保證一個事務不會被打斷,但是我們的程序還不知道是不是已經接收到信號了,并且把阻塞信號移除之后進程立刻就退出了,沒辦法去做一些收尾工作(比如關閉文件)。

處理信號

為了解決上面提到的問題,我們需要在信號發生的時候去做收尾工作,然后再退出進程。

pcntl 擴展提供了一些信號相關的函數,我們可以使用 pcntl_signal() 和 pcntl_signal_dispatch() 來注冊信號處理器和分發信號。

<?php
$sig_handler = function ($signo) {
    echo "收到信號 {$signo}" . PHP_EOL;
};
pcntl_signal(SIGINT, $sig_handler); // 給 SIGINT 信號注冊一個處理器

// 模擬耗時操作
echo "開始執行事務" . PHP_EOL;
$finish_time = time() + 5;
while(true) {
    if (time() > $finish_time) {
        echo "事務執行完畢" . PHP_EOL;
        break;
    }
}
pcntl_signal_dispatch(); // 分發信號

執行上面這段代碼并在 5 秒內按下 Ctrl + C,你會看到 sig_handler 被執行了;而如果不按下 Ctrl + C,那么 sig_handler 就不會被執行。

到這里你應該已經理解了 pcntl_signal() 和 pcntl_signal_dispatch() 的用法了,把它放到到剛剛的代碼試試

<?php

$sig_handler = function ($signo) {
    echo "收到信號 {$signo}" . PHP_EOL;
};
$sig_set = array(SIGINT, SIGTERM);
foreach ($sig_set as $sig) {
    pcntl_signal($sig, $sig_handler); // 注冊多個信號
}

// [1]

while (true) {
    // [2-1]
    pcntl_sigprocmask(SIG_BLOCK, $sig_set);
    // [2-2]

    // ...

    // [2-3]
    pcntl_sigprocmask(SIG_UNBLOCK, $sig_set);
    // [2-4]
}

// [3]

pcntl_signal_dispatch() 該放哪里呢?是 [1] [2] 還是 [3]?先動手試一下

然后你會發現,只有放在 [2] 才能讓信號處理器執行。同時這個實驗也告訴我們 pcntl_signal_dispatch() 要在信號發生后才會使處理器執行:放在 [1] 時,除非你手速足夠快,不然在你按下 Ctrl + C 或者是 kill 之前就已經執行過了;而放在 [3] 它就永遠沒機會執行。

至于放在 [2] 的哪個位置,我建議是放在 [2-4],因為這個時候已經處理完任務了。

拼起來

到這里你已經了解平滑關閉/重啟的原理了,我們把上面的半成品代碼(因為在收到信號后可能還會進入下一層循環)整理一下:

<?php

$running = true;

$sig_handler = function ($signo) use (&$running) {
    echo "收到信號 {$signo}" . PHP_EOL;
    // 做收尾工作
    $running = false;
};
$sig_set = array(SIGINT, SIGTERM, SIGUSR2 /* 熟悉的 USR2 信號不能漏 */);
foreach ($sig_set as $sig) {
    pcntl_signal($sig, $sig_handler); // 注冊多個信號
}


while ($running) {
    pcntl_sigprocmask(SIG_BLOCK, $sig_set);

    // ... 業務邏輯

    pcntl_sigprocmask(SIG_UNBLOCK, $sig_set);
    pcntl_signal_dispatch();
}

我們就得到了一個可以平滑程序的常駐進程框架,你也可以把它封裝成一個類。

“PHP怎么實現平滑關閉和重啟”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

香格里拉县| 利川市| 江永县| 海城市| 平原县| 镇坪县| 抚远县| 同江市| 安徽省| 城步| 五大连池市| 罗甸县| 荣昌县| 辰溪县| 吴堡县| 新巴尔虎左旗| 陵水| 兰溪市| 青川县| 手机| 灵台县| 微博| 宜兴市| 河南省| 津市市| 旺苍县| 胶州市| 灵璧县| 靖宇县| 深水埗区| 花莲市| 定日县| 丹江口市| 洪泽县| 互助| 搜索| 镇远县| 昌邑市| 垣曲县| 韶山市| 新竹市|