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
新聞熱點(diǎn)
疑難解答
圖片精選