国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Python > 正文

python使用fork實(shí)現(xiàn)守護(hù)進(jìn)程的方法

2020-01-04 16:21:55
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

os模塊中的fork方法可以創(chuàng)建一個(gè)子進(jìn)程。相當(dāng)于克隆了父進(jìn)程

os.fork()

子進(jìn)程運(yùn)行時(shí),os.fork方法會(huì)返回0;

 而父進(jìn)程運(yùn)行時(shí),os.fork方法會(huì)返回子進(jìn)程的PID號(hào)。

所以可以使用PID來(lái)區(qū)分兩個(gè)進(jìn)程:

 #!/usr/bin/env python #coding=utf8  from time import sleep import os  try: pid = os.fork() except OSError, e: pass  sleep(30)

運(yùn)行代碼,查看進(jìn)程:

[root@localhost ~]# python test2.py &[1] 2464[root@localhost ~]# ps -lF S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD4 S 0 2379 2377 0 80 0 - 28879 wait pts/1 00:00:00 bash0 S 0 2464 2379 0 80 0 - 31318 poll_s pts/1 00:00:00 python1 S 0 2465 2464 0 80 0 - 31318 poll_s pts/1 00:00:00 python0 R 0 2466 2379 0 80 0 - 37227 - pts/1 00:00:00 ps?

可以看出第二條python進(jìn)程就是第一條的子進(jìn)程。

如剛剛所說os.fork()方法區(qū)分子進(jìn)程和父進(jìn)程

#-*- coding:utf-8 -*- from time import sleepimport os print('start+++++++++++++')#創(chuàng)建子進(jìn)程之前聲明的變量source = 10try:    pid = os.fork()    print('pid=',pid)    if pid == 0: #子進(jìn)程        print("this is child process.")        source = source - 1 #在子進(jìn)程中source減1    else: #父進(jìn)程        print("this is parent process." )    print(source)except (OSError,e):    passprint('END---------------')  

面代碼中,在子進(jìn)程創(chuàng)建前,聲明了一個(gè)變量source,然后在子進(jìn)程中減1,最后打印出source的值,顯然父進(jìn)程打印出來(lái)的值應(yīng)該為10,子進(jìn)程打印出來(lái)的值應(yīng)該為9。

[root@localhost ~]# python test3.pystart+++++++++++++pid= 2550this is parent process.10END---------------pid= 0this is child process.9END---------------?  

 簡(jiǎn)單守護(hù)進(jìn)程例子:

def main():  ''' 程序要執(zhí)行的邏輯代碼 '''  pass  # 創(chuàng)建守護(hù)進(jìn)程函數(shù)def createDaemon():  ''' 第一塊(創(chuàng)建第一個(gè)子進(jìn)程) '''  # fork 第一個(gè)子進(jìn)程(如果fork成功,父進(jìn)程自殺,只留下第一個(gè)子進(jìn)程繼續(xù)向下運(yùn)行)  try:    if os.fork() > 0:      sys.exit(0)  except OSError, error:    print '(fork第一個(gè)子進(jìn)程失?。ゝork #1 failed: %d (%s)' % (error.errno, error.strerror)    sys.exit(1)  ''' 第一塊結(jié)束 '''   ###### 第一個(gè)進(jìn)程創(chuàng)建成功后,它的ppid = 1,已是一個(gè)守護(hù)里程了,但有些功能上還是有被限制。  ###### 所以下面再來(lái)創(chuàng)建一個(gè)子進(jìn)程。第二次創(chuàng)建的子進(jìn)程限制就沒那多了,有可能沒有,所以最安全。  ###### 下面來(lái)創(chuàng)建第二個(gè)子進(jìn)程?!?   os.chdir('/') # 把第一個(gè)子進(jìn)程的工作目錄切換到 / (根目錄)  os.setsid() # 第一個(gè)子進(jìn)程取得程序的權(quán)限  os.umask(0) # 第一個(gè)子進(jìn)程取得工作目錄的所有操作(目錄的rwx)    ''' 第二塊(創(chuàng)建第二個(gè)子進(jìn)程) '''  # fork 第二個(gè)子進(jìn)程(如果fork成功,第一個(gè)子進(jìn)程自殺,只留下新創(chuàng)建的第二個(gè)子進(jìn)程)  try:    pid = os.fork()    if pid > 0:      print 'Daemon PID %d' % pid      sys.exit(0)  except OSError, error:    print '(fork第二個(gè)子進(jìn)程失?。ゝork #2 failed: %d (%s)' % (error.errno, error.strerror)    sys.exit(1)  ''' 第二塊結(jié)束 '''    ####### 通過上面兩個(gè) try 語(yǔ)句塊,只留下了第二個(gè)子進(jìn)程在運(yùn)行了。這時(shí)第二個(gè)子進(jìn)程的ppid=1。  ####### 創(chuàng)建的第二個(gè)子進(jìn)程,可以說是一個(gè)不受限的守護(hù)進(jìn)程了。     # 重定向標(biāo)準(zhǔn)IO(因?yàn)橹挥械诙€(gè)子進(jìn)程在運(yùn)行了,所以也就是指定整個(gè)程序的輸入、輸出、錯(cuò)誤流)     # sys.stdout.flush() # 清除程序運(yùn)行空間的輸出流  # sys.stderr.flush() # 清除程序運(yùn)行空間的錯(cuò)誤流   # inputS = file("/dev/null", 'r')  # 定義一個(gè) inputS 文件對(duì)象  # outputS = file("/dev/null", 'a+') # 定義一個(gè) outputS 文件對(duì)象  # errorS = file("/dev/null", 'a+', 0) # 定義一個(gè) errorS 文件對(duì)象   # os.dup2(inputS.fileno(), sys.stdin.fileno()) # 把程序的輸入流重定向到上面定義的 inputS 文件對(duì)象上。  # os.dup2(so.fileno(), sys.stdout.fileno()) # 把程序的 輸出流 重定向到上面定義的 outputS 文件對(duì)象上。  # os.dup2(se.fileno(), sys.stderr.fileno()) # 把程序的 錯(cuò)誤流 重定向到上面定義的 errorS 文件對(duì)象上。   main() # main函數(shù)為真正程序邏輯代碼  if __name__ == "__main__":  if platform.system() == "Linux":      createDaemon()    else:      sys.exit()    

 帶控制參數(shù)的例子:

編寫守護(hù)進(jìn)程的基類,用于繼承:

# coding: utf-8 import osimport sysimport timeimport atexitimport signal  class Daemon:  def __init__(self, pidfile='/tmp/daemon.pid', stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):    self.stdin = stdin    self.stdout = stdout    self.stderr = stderr    self.pidfile = pidfile   def daemonize(self):    if os.path.exists(self.pidfile):      raise RuntimeError('Already running.')     # First fork (detaches from parent)    try:      if os.fork() > 0:        raise SystemExit(0)    except OSError as e:      raise RuntimeError('fork #1 faild: {0} ({1})/n'.format(e.errno, e.strerror))     os.chdir('/')    os.setsid()    os.umask(0o22)     # Second fork (relinquish session leadership)    try:      if os.fork() > 0:        raise SystemExit(0)    except OSError as e:      raise RuntimeError('fork #2 faild: {0} ({1})/n'.format(e.errno, e.strerror))     # Flush I/O buffers    sys.stdout.flush()    sys.stderr.flush()     # Replace file descriptors for stdin, stdout, and stderr    with open(self.stdin, 'rb', 0) as f:      os.dup2(f.fileno(), sys.stdin.fileno())    with open(self.stdout, 'ab', 0) as f:      os.dup2(f.fileno(), sys.stdout.fileno())    with open(self.stderr, 'ab', 0) as f:      os.dup2(f.fileno(), sys.stderr.fileno())     # Write the PID file    with open(self.pidfile, 'w') as f:      print(os.getpid(), file=f)     # Arrange to have the PID file removed on exit/signal    atexit.register(lambda: os.remove(self.pidfile))     signal.signal(signal.SIGTERM, self.__sigterm_handler)   # Signal handler for termination (required)  @staticmethod  def __sigterm_handler(signo, frame):    raise SystemExit(1)   def start(self):    try:      self.daemonize()    except RuntimeError as e:      print(e, file=sys.stderr)      raise SystemExit(1)     self.run()   def stop(self):    try:      if os.path.exists(self.pidfile):        with open(self.pidfile) as f:          os.kill(int(f.read()), signal.SIGTERM)      else:        print('Not running.', file=sys.stderr)        raise SystemExit(1)    except OSError as e:      if 'No such process' in str(e) and os.path.exists(self.pidfile):        os.remove(self.pidfile)   def restart(self):    self.stop()    self.start()   def run(self):  #繼承類重寫該方法    pass

  編寫自己的類:

 #導(dǎo)入剛剛編寫的基類 from daemon import Daemon #繼承 class MyTestDaemon(Daemon): #重寫run方法,就是你要后臺(tái)運(yùn)行的函數(shù)   def run(self):   #后臺(tái)運(yùn)行的函數(shù),比如shell輸出到自己定義的文件     sys.stdout.write('Daemon started with pid {}/n'.format(os.getpid()))     while True:       sys.stdout.write('Daemon Alive! {}/n'.format(time.ctime()))       sys.stdout.flush()        time.sleep(5)  if __name__ == '__main__':   PIDFILE = '/tmp/daemon-example.pid'   LOG = '/tmp/daemon-example.log'   daemon = MyTestDaemon(pidfile=PIDFILE, stdout=LOG, stderr=LOG)    if len(sys.argv) != 2:     print('Usage: {} [start|stop]'.format(sys.argv[0]), file=sys.stderr)     raise SystemExit(1)    if 'start' == sys.argv[1]:     daemon.start()   elif 'stop' == sys.argv[1]:     daemon.stop()   elif 'restart' == sys.argv[1]:     daemon.restart()   else:     print('Unknown command {!r}'.format(sys.argv[1]), file=sys.stderr)     raise SystemExit(1)

關(guān)于兩次fork

第二個(gè)fork不是必須的,只是為了防止進(jìn)程打開控制終端。

打開一個(gè)控制終端的條件是該進(jìn)程必須是session leader。第一次fork,setsid之后,子進(jìn)程成為session leader,進(jìn)程可以打開終端;第二次fork產(chǎn)生的進(jìn)程,不再是session leader,進(jìn)程則無(wú)法打開終端。

也就是說,只要程序?qū)崿F(xiàn)得好,控制程序不主動(dòng)打開終端,無(wú)第二次fork亦可。

代碼實(shí)現(xiàn)

# coding: utf-8import osimport sysimport timeimport atexitimport signalclass Daemon:  def __init__(self, pidfile='/tmp/daemon.pid', stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):    self.stdin = stdin    self.stdout = stdout    self.stderr = stderr    self.pidfile = pidfile  def daemonize(self):    if os.path.exists(self.pidfile):      raise RuntimeError('Already running.')    # First fork (detaches from parent)    try:      if os.fork() > 0:        raise SystemExit(0)    except OSError as e:      raise RuntimeError('fork #1 faild: {0} ({1})/n'.format(e.errno, e.strerror))    os.chdir('/')    os.setsid()    os.umask(0o22)    # Second fork (relinquish session leadership)    try:      if os.fork() > 0:        raise SystemExit(0)    except OSError as e:      raise RuntimeError('fork #2 faild: {0} ({1})/n'.format(e.errno, e.strerror))    # Flush I/O buffers    sys.stdout.flush()    sys.stderr.flush()    # Replace file descriptors for stdin, stdout, and stderr    with open(self.stdin, 'rb', 0) as f:      os.dup2(f.fileno(), sys.stdin.fileno())    with open(self.stdout, 'ab', 0) as f:      os.dup2(f.fileno(), sys.stdout.fileno())    with open(self.stderr, 'ab', 0) as f:      os.dup2(f.fileno(), sys.stderr.fileno())    # Write the PID file    with open(self.pidfile, 'w') as f:      print(os.getpid(), file=f)    # Arrange to have the PID file removed on exit/signal    atexit.register(lambda: os.remove(self.pidfile))    signal.signal(signal.SIGTERM, self.__sigterm_handler)  # Signal handler for termination (required)  @staticmethod  def __sigterm_handler(signo, frame):    raise SystemExit(1)  def start(self):    try:      self.daemonize()    except RuntimeError as e:      print(e, file=sys.stderr)      raise SystemExit(1)    self.run()  def stop(self):    try:      if os.path.exists(self.pidfile):        with open(self.pidfile) as f:          os.kill(int(f.read()), signal.SIGTERM)      else:        print('Not running.', file=sys.stderr)        raise SystemExit(1)    except OSError as e:      if 'No such process' in str(e) and os.path.exists(self.pidfile):         os.remove(self.pidfile)  def restart(self):    self.stop()    self.start()  def run(self):    pass

使用測(cè)試

import osimport sysimport timefrom daemon import Daemonclass MyTestDaemon(Daemon):  def run(self):    sys.stdout.write('Daemon started with pid {}/n'.format(os.getpid()))    while True:      sys.stdout.write('Daemon Alive! {}/n'.format(time.ctime()))      sys.stdout.flush()      time.sleep(5)if __name__ == '__main__':  PIDFILE = '/tmp/daemon-example.pid'  LOG = '/tmp/daemon-example.log'  daemon = MyTestDaemon(pidfile=PIDFILE, stdout=LOG, stderr=LOG)  if len(sys.argv) != 2:    print('Usage: {} [start|stop]'.format(sys.argv[0]), file=sys.stderr)    raise SystemExit(1)  if 'start' == sys.argv[1]:    daemon.start()  elif 'stop' == sys.argv[1]:    daemon.stop()  elif 'restart' == sys.argv[1]:    daemon.restart()  else:    print('Unknown command {!r}'.format(sys.argv[1]), file=sys.stderr)    raise SystemExit(1)
[daemon] python test.py start                     23:45:42[daemon] cat /tmp/daemon-example.pid                 23:45:498532[daemon] ps -ef|grep 8532 | grep -v grep               23:46:07 502 8532   1  0 11:45下午 ??     0:00.00 python test.py start[daemon] tail -f /tmp/daemon-example.log               23:46:20Daemon started with pid 8532Daemon Alive! Fri Dec 2 23:45:49 2016Daemon Alive! Fri Dec 2 23:45:54 2016Daemon Alive! Fri Dec 2 23:45:59 2016Daemon Alive! Fri Dec 2 23:46:04 2016Daemon Alive! Fri Dec 2 23:46:09 2016Daemon Alive! Fri Dec 2 23:46:14 2016Daemon Alive! Fri Dec 2 23:46:19 2016Daemon Alive! Fri Dec 2 23:46:24 2016Daemon Alive! Fri Dec 2 23:46:29 2016Daemon Alive! Fri Dec 2 23:46:34 2016[daemon] python test.py stop                     23:46:36[daemon] ps -ef|grep 8532 | grep -v grep               23:46:43


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到python教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 黄平县| 内乡县| 乐业县| 渭南市| 营山县| 行唐县| 河东区| 马山县| 河北省| 吐鲁番市| 沁水县| 永年县| 寻甸| 河间市| 都兰县| 清苑县| 内乡县| 九台市| 瑞金市| 凯里市| 琼中| 宜兴市| 个旧市| 中卫市| 镇坪县| 满洲里市| 勃利县| 林口县| 肥东县| 庆安县| 呈贡县| 陇南市| 乌什县| 绩溪县| 周口市| 循化| 宁城县| 全椒县| 崇仁县| 兴国县| 涿鹿县|