欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2017年11月16日 08:49:36   作者:zimsan  
守護(hù)進(jìn)程(Daemon)也稱(chēng)為精靈進(jìn)程是一種生存期較長(zhǎng)的一種進(jìn)程。它們獨(dú)立于控制終端并且周期性的執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。他們常常在系統(tǒng)引導(dǎo)裝入時(shí)啟動(dòng),在系統(tǒng)關(guān)閉時(shí)終止。

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 -l

F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD

4 S 0 2379 2377 0 80 0 - 28879 wait pts/1 00:00:00 bash

0 S 0 2464 2379 0 80 0 - 31318 poll_s pts/1 00:00:00 python

1 S 0 2465 2464 0 80 0 - 31318 poll_s pts/1 00:00:00 python

0 R 0 2466 2379 0 80 0 - 37227 - pts/1 00:00:00 ps​

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

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

#-*- coding:utf-8 -*-
 
from time import sleep
import os
 
print('start+++++++++++++')
#創(chuàng)建子進(jìn)程之前聲明的變量
source = 10
try:
    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):
    pass
print('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.py
start+++++++++++++
pid= 2550
this is parent process.
10
END---------------
pid= 0
this is child process.
9
END---------------​
  

 簡(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)程失敗)fork #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)程限制就沒(méi)那多了,有可能沒(méi)有,所以最安全。
  ###### 下面來(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é)束 '''
 
 
  ####### 通過(guò)上面兩個(gè) try 語(yǔ)句塊,只留下了第二個(gè)子進(jìn)程在運(yùn)行了。這時(shí)第二個(gè)子進(jìn)程的ppid=1。
  ####### 創(chuàng)建的第二個(gè)子進(jìn)程,可以說(shuō)是一個(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ù)的例子:

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

# coding: utf-8
 
import os
import sys
import time
import atexit
import 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):
  #繼承類(lèi)重寫(xiě)該方法
    pass

  編寫(xiě)自己的類(lèi):

 #導(dǎo)入剛剛編寫(xiě)的基類(lèi)
 from daemon import Daemon
 #繼承
 class MyTestDaemon(Daemon):
 #重寫(xiě)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)程打開(kāi)控制終端。

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

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

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

# coding: utf-8

import os
import sys
import time
import atexit
import 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

使用測(cè)試

import os
import sys
import time

from daemon import Daemon

class 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:49
8532
[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:20
Daemon started with pid 8532
Daemon Alive! Fri Dec 2 23:45:49 2016
Daemon Alive! Fri Dec 2 23:45:54 2016
Daemon Alive! Fri Dec 2 23:45:59 2016
Daemon Alive! Fri Dec 2 23:46:04 2016
Daemon Alive! Fri Dec 2 23:46:09 2016
Daemon Alive! Fri Dec 2 23:46:14 2016
Daemon Alive! Fri Dec 2 23:46:19 2016
Daemon Alive! Fri Dec 2 23:46:24 2016
Daemon Alive! Fri Dec 2 23:46:29 2016
Daemon 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)文章

  • Django中間件Middleware功能詳解

    Django中間件Middleware功能詳解

    Django中間件(Middleware)是Django框架中的一個(gè)功能,它允許開(kāi)發(fā)者在處理請(qǐng)求和響應(yīng)的過(guò)程中插入自定義代碼,中間件能夠在視圖函數(shù)執(zhí)行前后進(jìn)行操作,本文給大家介紹Django中間件Middleware功能,感興趣的朋友一起看看吧
    2024-10-10
  • matlab xlabel位置的設(shè)置方式

    matlab xlabel位置的設(shè)置方式

    這篇文章主要介紹了matlab xlabel位置的設(shè)置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • 淺析python中特殊文件和特殊函數(shù)

    淺析python中特殊文件和特殊函數(shù)

    這篇文章主要介紹了python中特殊文件和特殊函數(shù)的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • python常用web框架簡(jiǎn)單性能測(cè)試結(jié)果分享(包含django、flask、bottle、tornado)

    python常用web框架簡(jiǎn)單性能測(cè)試結(jié)果分享(包含django、flask、bottle、tornado)

    這篇文章主要介紹了python常用web框架簡(jiǎn)單性能測(cè)試結(jié)果分享(包含django、flask、bottle、tornado),需要的朋友可以參考下
    2014-08-08
  • python 如何比較字符串是否一樣

    python 如何比較字符串是否一樣

    這篇文章主要介紹了python 如何比較字符串是否一樣的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • pandas通過(guò)字典生成dataframe的方法步驟

    pandas通過(guò)字典生成dataframe的方法步驟

    這篇文章主要介紹了pandas通過(guò)字典生成dataframe的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Python二叉樹(shù)的遍歷操作示例【前序遍歷,中序遍歷,后序遍歷,層序遍歷】

    Python二叉樹(shù)的遍歷操作示例【前序遍歷,中序遍歷,后序遍歷,層序遍歷】

    這篇文章主要介紹了Python二叉樹(shù)的遍歷操作,結(jié)合實(shí)例形式分析了Python針對(duì)二叉樹(shù)的前序遍歷,中序遍歷,后序遍歷,層序遍歷等相關(guān)操作實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-12-12
  • python flask中動(dòng)態(tài)URL規(guī)則詳解

    python flask中動(dòng)態(tài)URL規(guī)則詳解

    今天小編就為大家分享一篇python flask中動(dòng)態(tài)URL規(guī)則詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • Python從文件中讀取指定的行以及在文件指定位置寫(xiě)入

    Python從文件中讀取指定的行以及在文件指定位置寫(xiě)入

    這篇文章主要給大家介紹了關(guān)于Python從文件中讀取指定的行及在文件中指定位置寫(xiě)入的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Python具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 基于Python List的賦值方法

    基于Python List的賦值方法

    今天小編就為大家分享一篇基于Python List的賦值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06

最新評(píng)論