最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2017年11月16日 08:49:36   作者:zimsan  
守護(hù)進(jìn)程(Daemon)也稱為精靈進(jìn)程是一種生存期較長的一種進(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來區(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)程。

如剛剛所說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)程打印出來的值應(yīng)該為10,子進(jìn)程打印出來的值應(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---------------​
  

 簡單守護(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ù)里程了,但有些功能上還是有被限制。
  ###### 所以下面再來創(chuàng)建一個(gè)子進(jìn)程。第二次創(chuàng)建的子進(jìn)程限制就沒那多了,有可能沒有,所以最安全。
  ###### 下面來創(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 語句塊,只留下了第二個(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 文件對象
  # outputS = file("/dev/null", 'a+') # 定義一個(gè) outputS 文件對象
  # errorS = file("/dev/null", 'a+', 0) # 定義一個(gè) errorS 文件對象
 
  # os.dup2(inputS.fileno(), sys.stdin.fileno()) # 把程序的輸入流重定向到上面定義的 inputS 文件對象上。
  # os.dup2(so.fileno(), sys.stdout.fileno()) # 把程序的 輸出流 重定向到上面定義的 outputS 文件對象上。
  # os.dup2(se.fileno(), sys.stderr.fileno()) # 把程序的 錯(cuò)誤流 重定向到上面定義的 errorS 文件對象上。
 
  main() # main函數(shù)為真正程序邏輯代碼
 
 
if __name__ == "__main__":
  if platform.system() == "Linux":
      createDaemon()
    else:
      sys.exit()
  
  

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

編寫守護(hù)進(jì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

  編寫自己的類:

 #導(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)程則無法打開終端。

也就是說,只要程序?qū)崿F(xiàn)得好,控制程序不主動(dòng)打開終端,無第二次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

使用測試

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)文章

  • Python函數(shù)進(jìn)階與文件操作詳情

    Python函數(shù)進(jìn)階與文件操作詳情

    這篇文章主要介紹了Python函數(shù)進(jìn)階與文件操作詳情,文章為榮啊主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08
  • python數(shù)據(jù)庫開發(fā)之MongoDB安裝及Python3操作MongoDB數(shù)據(jù)庫詳細(xì)方法與實(shí)例

    python數(shù)據(jù)庫開發(fā)之MongoDB安裝及Python3操作MongoDB數(shù)據(jù)庫詳細(xì)方法與實(shí)例

    這篇文章主要介紹了python數(shù)據(jù)庫開發(fā)之MongoDB安裝及Python3操作MongoDB數(shù)據(jù)庫詳細(xì)方法與實(shí)例,需要的朋友可以參考下
    2020-03-03
  • Python機(jī)器學(xué)習(xí)入門(一)序章

    Python機(jī)器學(xué)習(xí)入門(一)序章

    這篇文章主要介紹了Python機(jī)器學(xué)習(xí)入門知識(shí),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • 關(guān)于python pygame游戲進(jìn)行聲音添加的技巧

    關(guān)于python pygame游戲進(jìn)行聲音添加的技巧

    這篇文章主要給大家分享的是pygame游戲進(jìn)行聲音添加的方法,這文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
    2021-10-10
  • Python bisect_left 函數(shù)使用場景詳解

    Python bisect_left 函數(shù)使用場景詳解

    在Python的編程世界中,數(shù)據(jù)處理和搜索操作是非常常見的任務(wù),bisect_left函數(shù)是Python標(biāo)準(zhǔn)庫bisect模塊中的一個(gè)強(qiáng)大工具,接下來,我們將詳細(xì)探討bisect_left函數(shù)的使用場景,需要的朋友可以參考下
    2024-11-11
  • 什么是python類屬性

    什么是python類屬性

    在本篇文章里小編給大家分享了關(guān)于python類屬性的相關(guān)知識(shí)點(diǎn),需要的朋友們可以參考學(xué)習(xí)下。
    2020-06-06
  • Django中STATIC_ROOT和STATIC_URL及STATICFILES_DIRS淺析

    Django中STATIC_ROOT和STATIC_URL及STATICFILES_DIRS淺析

    這篇文章主要給大家介紹了關(guān)于Django中STATIC_ROOT和STATIC_URL及STATICFILES_DIRS的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧
    2018-05-05
  • Python字符串內(nèi)置函數(shù)功能與用法總結(jié)

    Python字符串內(nèi)置函數(shù)功能與用法總結(jié)

    這篇文章主要介紹了Python字符串內(nèi)置函數(shù)功能與用法,結(jié)合實(shí)例形式總結(jié)分析了Python常見字符串操作函數(shù)的功能、分類、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-04-04
  • Numpy中np.random.rand()和np.random.randn() 用法和區(qū)別詳解

    Numpy中np.random.rand()和np.random.randn() 用法和區(qū)別詳解

    這篇文章主要介紹了Numpy中np.random.rand()和np.random.randn() 用法和區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • pytorch更新tensor中指定index位置的值scatter_add_問題

    pytorch更新tensor中指定index位置的值scatter_add_問題

    這篇文章主要介紹了pytorch更新tensor中指定index位置的值scatter_add_問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06

最新評(píng)論

宜宾市| 肇东市| 克东县| 长治县| 武清区| 奈曼旗| 长汀县| 隆尧县| 合水县| 新蔡县| 社旗县| 邹平县| 绥江县| 屏东市| 收藏| 环江| 六枝特区| 泰安市| 松江区| 安塞县| 岑溪市| 九龙城区| 深水埗区| 建始县| 土默特右旗| 扬州市| 哈巴河县| 岚皋县| 芜湖县| 瑞金市| 东兴市| 冕宁县| 内江市| 聂荣县| 星子县| 东安县| 图木舒克市| 达州市| 张掖市| 会东县| 乡宁县|