php守護(hù)進(jìn)程 加linux命令nohup實(shí)現(xiàn)任務(wù)每秒執(zhí)行一次
更新時(shí)間:2011年07月04日 22:18:05 作者:
那么有了這個(gè)命令以后我們php就寫成shell 腳本使用循環(huán)來(lái)讓我們腳本一直運(yùn)行下去,不管我們終端窗口是否關(guān)閉都能夠讓我們php 腳本一直運(yùn)行下去。
Unix中 nohup 命令功能就是不掛斷地運(yùn)行命令,同時(shí) nohup 把程序的所有輸出到放到當(dāng)前目錄 nohup.out 文件中,如果文件不可寫,則放到 <用戶主目錄>/nohup.out 文件中。那么有了這個(gè)命令以后我們php就寫成shell 腳本使用循環(huán)來(lái)讓我們腳本一直運(yùn)行下去,不管我們終端窗口是否關(guān)閉都能夠讓我們php 腳本一直運(yùn)行下去。
馬上動(dòng)手寫個(gè) PHP 小程序,功能為每30秒記錄時(shí)間,寫入到文件
# 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 文件可執(zhí)行權(quán)限:
# chmod +x for_ever.php
讓它在再后臺(tái)執(zhí)行:
# nohup /home/andy/for_ever.php.php &
記得最后加上 & 符號(hào),這樣才能夠跑到后臺(tái)去運(yùn)行
執(zhí)行上述命令后出現(xiàn)如下提示:
[1] 5157
nohup: appending output to 'nohup.out'
所有命令執(zhí)行輸出信息都會(huì)放到 nohup.out 文件中
這時(shí)你可以打開 for_ever.php 同目錄下的 for_ever.txt 和 nohup.out 看看效果!
好了,它會(huì)永遠(yuǎn)運(yùn)行下去了,怎么結(jié)束它呢?
# 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
找到進(jìn)程號(hào) 5157 殺之,你將看到
[1]+ Killed nohup /home/andy/for_ever.php
OK!
====================
在很多項(xiàng)目中,或許有很多類似的后端腳本需要通過(guò)crontab定時(shí)執(zhí)行。比如每10秒檢查一下用戶狀態(tài)。腳本如下:
@file: /php_scripts/scan_userstatus.php
#!/usr/bin/env php -q
$status = has_goaway();
if ($status) {
//done
}
?>
通過(guò)crontab定時(shí)執(zhí)行腳本scan_userstatus.php
#echo “*:*/10 * * * * /php_scripts/scan_userstatus.php”
這樣,每隔10秒鐘,就會(huì)執(zhí)行該腳本。
我們發(fā)現(xiàn),在短時(shí)間內(nèi),該腳本的內(nèi)存資源還沒有釋放完,又啟用了新的腳本。也就是說(shuō):新腳本啟動(dòng)了,舊腳本占用的資源還沒有如愿釋放。如此,日積月累,浪費(fèi)了很多內(nèi)存資源。我們對(duì)這個(gè)腳本進(jìn)行了一下改進(jìn),改進(jìn)后如下:
@file: /php_scripts/scan_userstatus.php
#/usr/bin/env php -q
while (1) {
$status = has_goaway();
if ($status) {
//done
}
usleep(10000000);
}
?>
這樣,不需要crontab了??梢酝ㄟ^(guò)以下命令執(zhí)行腳本,達(dá)到相同的功能效果
#chmod +x /php_scripts/scan_userstatus.php
#nohup /php_scripts/scan_userstatus.php &
在這里,我們通過(guò)&將腳本放到后臺(tái)運(yùn)行,為了防止隨著終端會(huì)話窗口關(guān)閉進(jìn)程被殺,我們使用了nohup命令。那么有沒有辦法,不使nohup命令,也能夠運(yùn)行呢,就像Unin/Linux Daemon一樣。接下來(lái),就是我們要講的守護(hù)進(jìn)程函數(shù)。
什么是守護(hù)進(jìn)程?一個(gè)守護(hù)進(jìn)程通常補(bǔ)認(rèn)為是一個(gè)不對(duì)終端進(jìn)行控制的后臺(tái)任務(wù)。它有三個(gè)很顯著的特征:在后臺(tái)運(yùn)行,與啟動(dòng)他的進(jìn)程脫離,無(wú)須控制終端。常用的實(shí)現(xiàn)方式是fork() -> setsid() -> fork() 詳細(xì)如下:
@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);
}
}
?>
實(shí)現(xiàn)了守護(hù)進(jìn)程函數(shù)以后,則可以建立一個(gè)常駐進(jìn)程,所以只需要執(zhí)行一次:
#/php_scripts/scan_userstatus.php
這里較為關(guān)鍵的二個(gè)php函數(shù)是pcntl_fork()和posix_setsid()。fork()一個(gè)進(jìn)程,則表示創(chuàng)建了一個(gè)運(yùn)行進(jìn)程的副本,副本被認(rèn)為是子進(jìn)程,而原始進(jìn)程被認(rèn)為是父進(jìn)程。當(dāng)fork()運(yùn)行之后,則可以脫離啟動(dòng)他的進(jìn)程與終端控制等,也意味著父進(jìn)程可以自由退出。 pcntl_fork()返回值,-1表示執(zhí)行失敗,0表示在子進(jìn)程中,而返進(jìn)程ID號(hào),則表示在父進(jìn)程中。在這里,退出父進(jìn)程。setsid(),它首先使新進(jìn)程成為一個(gè)新會(huì)話的“領(lǐng)導(dǎo)者”,最后使該進(jìn)程不再控制終端,這也是成為守護(hù)進(jìn)程最關(guān)鍵的一步,這意味著,不會(huì)隨著終端關(guān)閉而強(qiáng)制退出進(jìn)程。對(duì)于一個(gè)不會(huì)被中斷的常駐進(jìn)程來(lái)說(shuō),這是很關(guān)鍵的一步。進(jìn)行最后一次fork(),這一步不是必須的,但通常都這么做,它最大的意義是防止獲得控制終端。(在直接打開一個(gè)終端設(shè)備,而且沒有使用O_NOCTTY標(biāo)志的情況下, 會(huì)獲得控制終端).
其它事項(xiàng)說(shuō)明:
1) chdir() 將守護(hù)進(jìn)程放到總是存在的目錄中,另外一個(gè)好處是,你的常駐進(jìn)程不會(huì)限制你umount一個(gè)文件系統(tǒng)。
2)umask() 設(shè)置文件模式,創(chuàng)建掩碼到最大的允許限度。如果一個(gè)守護(hù)進(jìn)程需要?jiǎng)?chuàng)建具有可讀,可寫權(quán)限的文件,一個(gè)被繼承的具有更嚴(yán)格權(quán)限的掩碼會(huì)有反作用。
3)fclose(STDIN), fclose(STDOUT), fclose(STDERR) 關(guān)閉標(biāo)準(zhǔn)I/O流。注意,如果有輸出(echo),則守護(hù)進(jìn)程會(huì)失敗。所以通常將STDIN, STDOUT, STDERR重定向某個(gè)指定文件.
馬上動(dòng)手寫個(gè) PHP 小程序,功能為每30秒記錄時(shí)間,寫入到文件
復(fù)制代碼 代碼如下:
# 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 文件可執(zhí)行權(quán)限:
# chmod +x for_ever.php
讓它在再后臺(tái)執(zhí)行:
# nohup /home/andy/for_ever.php.php &
記得最后加上 & 符號(hào),這樣才能夠跑到后臺(tái)去運(yùn)行
執(zhí)行上述命令后出現(xiàn)如下提示:
[1] 5157
nohup: appending output to 'nohup.out'
所有命令執(zhí)行輸出信息都會(huì)放到 nohup.out 文件中
這時(shí)你可以打開 for_ever.php 同目錄下的 for_ever.txt 和 nohup.out 看看效果!
好了,它會(huì)永遠(yuǎn)運(yùn)行下去了,怎么結(jié)束它呢?
# 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
找到進(jìn)程號(hào) 5157 殺之,你將看到
[1]+ Killed nohup /home/andy/for_ever.php
OK!
====================
在很多項(xiàng)目中,或許有很多類似的后端腳本需要通過(guò)crontab定時(shí)執(zhí)行。比如每10秒檢查一下用戶狀態(tài)。腳本如下:
@file: /php_scripts/scan_userstatus.php
復(fù)制代碼 代碼如下:
#!/usr/bin/env php -q
$status = has_goaway();
if ($status) {
//done
}
?>
通過(guò)crontab定時(shí)執(zhí)行腳本scan_userstatus.php
#echo “*:*/10 * * * * /php_scripts/scan_userstatus.php”
這樣,每隔10秒鐘,就會(huì)執(zhí)行該腳本。
我們發(fā)現(xiàn),在短時(shí)間內(nèi),該腳本的內(nèi)存資源還沒有釋放完,又啟用了新的腳本。也就是說(shuō):新腳本啟動(dòng)了,舊腳本占用的資源還沒有如愿釋放。如此,日積月累,浪費(fèi)了很多內(nèi)存資源。我們對(duì)這個(gè)腳本進(jìn)行了一下改進(jìn),改進(jìn)后如下:
@file: /php_scripts/scan_userstatus.php
復(fù)制代碼 代碼如下:
#/usr/bin/env php -q
while (1) {
$status = has_goaway();
if ($status) {
//done
}
usleep(10000000);
}
?>
這樣,不需要crontab了??梢酝ㄟ^(guò)以下命令執(zhí)行腳本,達(dá)到相同的功能效果
#chmod +x /php_scripts/scan_userstatus.php
#nohup /php_scripts/scan_userstatus.php &
在這里,我們通過(guò)&將腳本放到后臺(tái)運(yùn)行,為了防止隨著終端會(huì)話窗口關(guān)閉進(jìn)程被殺,我們使用了nohup命令。那么有沒有辦法,不使nohup命令,也能夠運(yùn)行呢,就像Unin/Linux Daemon一樣。接下來(lái),就是我們要講的守護(hù)進(jìn)程函數(shù)。
什么是守護(hù)進(jìn)程?一個(gè)守護(hù)進(jìn)程通常補(bǔ)認(rèn)為是一個(gè)不對(duì)終端進(jìn)行控制的后臺(tái)任務(wù)。它有三個(gè)很顯著的特征:在后臺(tái)運(yùn)行,與啟動(dòng)他的進(jìn)程脫離,無(wú)須控制終端。常用的實(shí)現(xiàn)方式是fork() -> setsid() -> fork() 詳細(xì)如下:
@file: /php_scripts/scan_userstatus.php
復(fù)制代碼 代碼如下:
#/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);
}
}
?>
實(shí)現(xiàn)了守護(hù)進(jìn)程函數(shù)以后,則可以建立一個(gè)常駐進(jìn)程,所以只需要執(zhí)行一次:
#/php_scripts/scan_userstatus.php
這里較為關(guān)鍵的二個(gè)php函數(shù)是pcntl_fork()和posix_setsid()。fork()一個(gè)進(jìn)程,則表示創(chuàng)建了一個(gè)運(yùn)行進(jìn)程的副本,副本被認(rèn)為是子進(jìn)程,而原始進(jìn)程被認(rèn)為是父進(jìn)程。當(dāng)fork()運(yùn)行之后,則可以脫離啟動(dòng)他的進(jìn)程與終端控制等,也意味著父進(jìn)程可以自由退出。 pcntl_fork()返回值,-1表示執(zhí)行失敗,0表示在子進(jìn)程中,而返進(jìn)程ID號(hào),則表示在父進(jìn)程中。在這里,退出父進(jìn)程。setsid(),它首先使新進(jìn)程成為一個(gè)新會(huì)話的“領(lǐng)導(dǎo)者”,最后使該進(jìn)程不再控制終端,這也是成為守護(hù)進(jìn)程最關(guān)鍵的一步,這意味著,不會(huì)隨著終端關(guān)閉而強(qiáng)制退出進(jìn)程。對(duì)于一個(gè)不會(huì)被中斷的常駐進(jìn)程來(lái)說(shuō),這是很關(guān)鍵的一步。進(jìn)行最后一次fork(),這一步不是必須的,但通常都這么做,它最大的意義是防止獲得控制終端。(在直接打開一個(gè)終端設(shè)備,而且沒有使用O_NOCTTY標(biāo)志的情況下, 會(huì)獲得控制終端).
其它事項(xiàng)說(shuō)明:
1) chdir() 將守護(hù)進(jìn)程放到總是存在的目錄中,另外一個(gè)好處是,你的常駐進(jìn)程不會(huì)限制你umount一個(gè)文件系統(tǒng)。
2)umask() 設(shè)置文件模式,創(chuàng)建掩碼到最大的允許限度。如果一個(gè)守護(hù)進(jìn)程需要?jiǎng)?chuàng)建具有可讀,可寫權(quán)限的文件,一個(gè)被繼承的具有更嚴(yán)格權(quán)限的掩碼會(huì)有反作用。
3)fclose(STDIN), fclose(STDOUT), fclose(STDERR) 關(guān)閉標(biāo)準(zhǔn)I/O流。注意,如果有輸出(echo),則守護(hù)進(jìn)程會(huì)失敗。所以通常將STDIN, STDOUT, STDERR重定向某個(gè)指定文件.
您可能感興趣的文章:
- linux shell實(shí)現(xiàn)守護(hù)進(jìn)程腳本
- 詳解Linux中的守護(hù)進(jìn)程
- linux下如何創(chuàng)建守護(hù)進(jìn)程的步驟
- C語(yǔ)言編寫Linux守護(hù)進(jìn)程實(shí)例
- Python實(shí)現(xiàn)Linux下守護(hù)進(jìn)程的編寫方法
- Java實(shí)現(xiàn)Linux下雙守護(hù)進(jìn)程
- linux 守護(hù)進(jìn)程詳解及建立守護(hù)進(jìn)程
- Linux守護(hù)進(jìn)程的啟動(dòng)方法
- linux下的守護(hù)進(jìn)程
- linux守護(hù)進(jìn)程服務(wù)daemon、nohup、systemd的區(qū)別
相關(guān)文章
PHP+Ajax異步通訊實(shí)現(xiàn)用戶名郵箱驗(yàn)證是否已注冊(cè)( 2種方法實(shí)現(xiàn))
在網(wǎng)站注冊(cè)用戶時(shí)使用,主要為了無(wú)刷新異步驗(yàn)證用戶輸入的用戶名或者Email是否已注冊(cè)。2011-12-12
php AJAX實(shí)例根據(jù)郵編自動(dòng)完成地址信息
當(dāng)客戶輸入一個(gè)POSTCODE后,zipcode.PHP就接收到它,然后進(jìn)行從數(shù)據(jù)表中取出對(duì)應(yīng)的資料,再按一定的格式返回給客戶端(此處是以 | 分隔)。最后客戶端接收返回的資料,顯示在頁(yè)面上。2008-11-11
Yii2框架實(shí)現(xiàn)數(shù)據(jù)庫(kù)常用操作總結(jié)
本篇文章主要介紹了Yii2框架實(shí)現(xiàn)數(shù)據(jù)庫(kù)常用操作總結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
laravel框架中間件 except 和 only 的用法示例
這篇文章主要介紹了laravel框架中間件 except 和 only 的用法,簡(jiǎn)單說(shuō)明了中間件 except 和 only的功能,并結(jié)合實(shí)例形式分析了laravel框架中間件 except 和 only 相關(guān)使用技巧,需要的朋友可以參考下2019-07-07

