python实现守护进程_守护进程原理及Python实现
守護(hù)進(jìn)程原理及Python實(shí)現(xiàn)
守護(hù)進(jìn)程,不依賴(lài)于終端,在后臺(tái)運(yùn)行的程序,通常稱(chēng)為daemon(?di?m?n或?de?m?n)。
一些常見(jiàn)的Linux軟件通常都是已守護(hù)進(jìn)程的方式運(yùn)行,比如:
nginx
redis
memcached
守護(hù)進(jìn)程的原理:
通過(guò)fork() 復(fù)刻出子進(jìn)程,并通過(guò)setsid()創(chuàng)建新會(huì)話(huà),成為會(huì)話(huà)首領(lǐng);同時(shí)結(jié)束原來(lái)的父進(jìn)程,使得復(fù)刻出來(lái)的子進(jìn)程脫離終端而運(yùn)行。
守護(hù)進(jìn)程Python代碼實(shí)現(xiàn):
def daemon_start(self):
try:
# 第1次fork,并結(jié)束父進(jìn)程
pid = os.fork()
if pid > 0:
sys.exit(0)
except Exception as e:
sys.exit(1)
# 創(chuàng)建新會(huì)話(huà),并成為會(huì)話(huà)首領(lǐng)
os.setsid()
os.chdir(self.workdir)
os.umask(self.umask)
try:
# 第2次fork,結(jié)束當(dāng)前這個(gè)子進(jìn)程,fork出來(lái)的孫子進(jìn)程由于不是進(jìn)程首領(lǐng),無(wú)法再次獲取終端(這里的子進(jìn)程,孫子進(jìn)程都是相對(duì)于最開(kāi)始的那個(gè)初始進(jìn)程而言)
pid = os.fork()
if pid > 0:
sys.exit(0)
except Exception as e:
sys.exit(1)
def handle_exit(signum, _):
sys.exit(0)
# 孫子進(jìn)程注冊(cè)信號(hào)處理方式
signal.signal(signal.SIGINT, handle_exit)
signal.signal(signal.SIGTERM, handle_exit)
signal.signal(signal.SIGHUP, signal.SIG_IGN)
# 孫子進(jìn)程是守護(hù)進(jìn)程,不存在標(biāo)準(zhǔn)輸入輸出,所以關(guān)閉。
sys.stdin.close()
核心函數(shù)說(shuō)明:
os.fork(): 對(duì)進(jìn)程進(jìn)行復(fù)刻;值得特別注意的是fork之后,原來(lái)的進(jìn)程并沒(méi)有終止,而是繼續(xù)存在,被成為父進(jìn)程;也就是說(shuō),在fork成功后,一共會(huì)存在2個(gè)進(jìn)程,1個(gè)是原來(lái)的進(jìn)程,稱(chēng)為父進(jìn)程,1個(gè)是新創(chuàng)建的進(jìn)程,稱(chēng)為子進(jìn)程。父進(jìn)程和子進(jìn)程都會(huì)從fork的位置開(kāi)始繼續(xù)向下執(zhí)行,不同的是父進(jìn)程中,得到的fork返回值為子進(jìn)程的進(jìn)程號(hào),而子進(jìn)程中得到的是0。通過(guò)這個(gè)返回值,就能判斷哪個(gè)是父進(jìn)程,哪個(gè)是子進(jìn)程。以上這點(diǎn)值得特別注意,這與我們以往理解的程序執(zhí)行邏輯完全不同。
os.setsid():創(chuàng)建新的會(huì)話(huà),并成為會(huì)話(huà)首領(lǐng)。
os.chdir():修改當(dāng)前工作目錄路徑,防止目錄被移除導(dǎo)致守護(hù)進(jìn)程異常。
os.umask():設(shè)置文件創(chuàng)建模式屏蔽字,使得創(chuàng)建文件不受系統(tǒng)默認(rèn)權(quán)限的影響。
常見(jiàn)問(wèn)題:
1.第1次fork子進(jìn)程已經(jīng)脫離終端,為什么還要第2次fork,第2次fork是否必須?
第2次fork并不是必須的,實(shí)際上,很多流行的開(kāi)源軟件的守護(hù)進(jìn)程并沒(méi)有進(jìn)行第2次fork。第2次fork的目的在于防止第1次fork出來(lái)的進(jìn)程再次獲得終端,第2次fork后,產(chǎn)生的孫子進(jìn)程不再是會(huì)話(huà)首領(lǐng),也就沒(méi)有再次獲得終端的能力。
void daemonize(void) {
int fd;
if (fork() != 0) exit(0); /* parent exits */
setsid(); /* create a new session */
/* Every output goes to /dev/null. If Redis is daemonized but
* the 'logfile' is set to 'stdout' in the configuration file
* it will not log at all. */
if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) close(fd);
}
}
2.進(jìn)程已經(jīng)脫離終端,如何讓它停止或者重啟?
每一個(gè)進(jìn)程都有一個(gè)進(jìn)程id,即pid,通常程序啟動(dòng)后,會(huì)把pid寫(xiě)入到/var/run/目錄下的某個(gè)文件里,通過(guò)發(fā)送信號(hào)量給pid,即可操作相關(guān)進(jìn)程。示例代碼中的“進(jìn)程注冊(cè)信號(hào)處理方式”就是用來(lái)響應(yīng)信號(hào)量的,守護(hù)進(jìn)程可以針對(duì)不同的信號(hào),做出不同的反應(yīng)。
總結(jié)
以上是生活随笔為你收集整理的python实现守护进程_守护进程原理及Python实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux系统间文件双向同步搭建Unis
- 下一篇: 运行返回签名不正确_如果调用约定不匹配,