php守護進程 加linux命令nohup實現任務每秒執行一次

來源:互聯網
上載者:User

Unix中 nohup 命令功能就是不掛斷地運行命令,同時 nohup 把程式的所有輸出到放到目前的目錄 nohup.out 檔案中,如果檔案不可寫,則放到 <使用者主目錄>/nohup.out 檔案中。那麼有了這個命令以後我們php就寫成shell 指令碼使用迴圈來讓我們指令碼一直運行下去,不管我們終端視窗是否關閉都能夠讓我們php 指令碼一直運行下去。
馬上動手寫個 PHP 小程式,功能為每30秒記錄時間,寫入到檔案 複製代碼 代碼如下:# vi for_ever.php
#! /usr/local/php/bin/php
define('ROOT', dirname(__FILE__).'/');
set_time_limit(0);
while (true) {
file_put_contents(ROOT.'for_ever.txt', date('Y-m-d H:i:s')."\n", FILE_APPEND);
echo date('Y-m-d H:i:s'), ' OK!';
sleep(30);
}
?>

儲存退出,然後賦予 for_ever.php 檔案可執行許可權:
# chmod +x for_ever.php
讓它在再後台執行:
# nohup /home/andy/for_ever.php.php &
記得最後加上 & 符號,這樣才能夠跑到後台去運行
執行上述命令後出現如下提示:
[1] 5157
nohup: appending output to 'nohup.out'
所有命令執行輸出資訊都會放到 nohup.out 檔案中
這時你可以開啟 for_ever.php 同目錄下的 for_ever.txt 和 nohup.out 看看效果!
好了,它會永遠運行下去了,怎麼結束它呢?
# ps
PID TTY TIME CMD
4247 pts/1 00:00:00 bash
5157 pts/1 00:00:00 for_ever.php
5265 pts/1 00:00:00 ps
# kill -9 5157
找到進程號 5157 殺之,你將看到
[1]+ Killed nohup /home/andy/for_ever.php
OK!
====================
在很多項目中,或許有很多類似的後端指令碼需要通過crontab定時執行。比如每10秒檢查一下使用者狀態。指令碼如下:
@file: /php_scripts/scan_userstatus.php 複製代碼 代碼如下:#!/usr/bin/env php -q
$status = has_goaway();
if ($status) {
//done
}
?>

通過crontab定時執行指令碼scan_userstatus.php
#echo “*:*/10 * * * * /php_scripts/scan_userstatus.php”
這樣,每隔10秒鐘,就會執行該指令碼。
我們發現,在短時間內,該指令碼的記憶體資源還沒有釋放完,又啟用了新的指令碼。也就是說:新指令碼啟動了,舊指令碼佔用的資源還沒有如願釋放。如此,日積月累,浪費了很多記憶體資源。我們對這個指令碼進行了一下改進,改進後如下:
@file: /php_scripts/scan_userstatus.php 複製代碼 代碼如下:#/usr/bin/env php -q
while (1) {
$status = has_goaway();
if ($status) {
//done
}
usleep(10000000);
}
?>

這樣,不需要crontab了。可以通過以下命令執行指令碼,達到相同的功能效果
#chmod +x /php_scripts/scan_userstatus.php
#nohup /php_scripts/scan_userstatus.php &
在這裡,我們通過&將指令碼放到後台運行,為了防止隨著終端會話視窗關閉進程被殺,我們使用了nohup命令。那麼有沒有辦法,不使nohup命令,也能夠運行呢,就像Unin/Linux Daemon一樣。接下來,就是我們要講的守護進程函數。
什麼是守護進程?一個守護進程通常補認為是一個不對終端進行控制的背景工作。它有三個很顯著的特徵:在後台運行,與啟動他的進程脫離,無須控制終端。常用的實現方式是fork() -> setsid() -> fork() 詳細如下:
@file: /php_scripts/scan_userstatus.php 複製代碼 代碼如下:#/usr/bin/env php -q
daemonize();
while (1) {
$status = has_goaway();
if ($status) {
//done
}
usleep(10000000);
}
function daemonize() {
$pid = pcntl_fork();
if ($pid === -1 ) {
return FALSE;
} else if ($pid) {
usleep(500);
exit(); //exit parent
}
chdir("/");
umask(0);
$sid = posix_setsid();
if (!$sid) {
return FALSE;
}
$pid = pcntl_fork();
if ($pid === -1) {
return FALSE;
} else if ($pid) {
usleep(500);
exit(0);
}
if (defined('STDIN')) {
fclose(STDIN);
}
if (defined('STDOUT')){
fclose(STDOUT);
}
if (defined('STDERR')) {
fclose(STDERR);
}
}
?>

實現了守護進程函數以後,則可以建立一個常駐進程,所以只需要執行一次:
#/php_scripts/scan_userstatus.php
這裡較為關鍵的二個php函數是pcntl_fork()和posix_setsid()。fork()一個進程,則表示建立了一個運行進程的副本,副本被認為是子進程,而原始進程被認為是父進程。當fork()運行之後,則可以脫離啟動他的進程與終端控制等,也意味著父進程可以自由退出。 pcntl_fork()傳回值,-1表示執行失敗,0表示在子進程中,而返進程ID號,則表示在父進程中。在這裡,退出父進程。setsid(),它首先使新進程成為一個新會話的“領導者”,最後使該進程不再控制終端,這也是成為守護進程最關鍵的一步,這意味著,不會隨著終端關閉而強制退出進程。對於一個不會被中斷的常駐進程來說,這是很關鍵的一步。進行最後一次fork(),這一步不是必須的,但通常都這麼做,它最大的意義是防止獲得控制終端。(在直接開啟一個終端裝置,而且沒有使用O_NOCTTY標誌的情況下, 會獲得控制終端).
其它事項說明:
1) chdir() 將守護進程放到總是存在的目錄中,另外一個好處是,你的常駐進程不會限制你umount一個檔案系統。
2)umask() 設定檔案模式,建立掩碼到最大的允許限度。如果一個守護進程需要建立具有可讀,可寫入權限的檔案,一個被繼承的具有更嚴格許可權的掩碼會有反作用。
3)fclose(STDIN), fclose(STDOUT), fclose(STDERR) 關閉標準I/O流。注意,如果有輸出(echo),則守護進程會失敗。所以通常將STDIN, STDOUT, STDERR重新導向某個指定檔案.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.