我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python使用fork实现守护进程的方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python使用fork实现守护进程的方法

os模块中的fork方法可以创建一个子进程。相当于克隆了父进程

os.fork()

子进程运行时,os.fork方法会返回0;

而父进程运行时,os.fork方法会返回子进程的PID号。

所以可以使用PID来区分两个进程:


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

运行代码,查看进程:


[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进程就是第一条的子进程。

如刚刚所说os.fork()方法区分子进程和父进程


#-*- coding:utf-8 -*-
 
from time import sleep
import os
 
print('start+++++++++++++')
#创建子进程之前声明的变量
source = 10
try:
    pid = os.fork()
    print('pid=',pid)
    if pid == 0: #子进程
        print("this is child process.")
        source = source - 1 #在子进程中source减1
    else: #父进程
        print("this is parent process." )
    print(source)
except (OSError,e):
    pass
print('END---------------')
  

面代码中,在子进程创建前,声明了一个变量source,然后在子进程中减1,最后打印出source的值,显然父进程打印出来的值应该为10,子进程打印出来的值应该为9。


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

简单守护进程例子:


def main():
  ''' 程序要执行的逻辑代码 '''
  pass
 
 
# 创建守护进程函数
def createDaemon():
  ''' 第一块(创建第一个子进程) '''
  # fork 第一个子进程(如果fork成功,父进程自杀,只留下第一个子进程继续向下运行)
  try:
    if os.fork() > 0:
      sys.exit(0)
  except OSError, error:
    print '(fork第一个子进程失败)fork #1 failed: %d (%s)' % (error.errno, error.strerror)
    sys.exit(1)
  ''' 第一块结束 '''
 
  ###### 第一个进程创建成功后,它的ppid = 1,已是一个守护里程了,但有些功能上还是有被限制。
  ###### 所以下面再来创建一个子进程。第二次创建的子进程限制就没那多了,有可能没有,所以最安全。
  ###### 下面来创建第二个子进程。 
 
 
  os.chdir('/') # 把第一个子进程的工作目录切换到 / (根目录)
  os.setsid() # 第一个子进程取得程序的权限
  os.umask(0) # 第一个子进程取得工作目录的所有操作(目录的rwx)
 
 
  ''' 第二块(创建第二个子进程) '''
  # fork 第二个子进程(如果fork成功,第一个子进程自杀,只留下新创建的第二个子进程)
  try:
    pid = os.fork()
    if pid > 0:
      print 'Daemon PID %d' % pid
      sys.exit(0)
  except OSError, error:
    print '(fork第二个子进程失败)fork #2 failed: %d (%s)' % (error.errno, error.strerror)
    sys.exit(1)
  ''' 第二块结束 '''
 
 
  ####### 通过上面两个 try 语句块,只留下了第二个子进程在运行了。这时第二个子进程的ppid=1。
  ####### 创建的第二个子进程,可以说是一个不受限的守护进程了。
 
 
 
  # 重定向标准IO(因为只有第二个子进程在运行了,所以也就是指定整个程序的输入、输出、错误流)
   
  # sys.stdout.flush() # 清除程序运行空间的输出流
  # sys.stderr.flush() # 清除程序运行空间的错误流
 
  # inputS = file("/dev/null", 'r')  # 定义一个 inputS 文件对象
  # outputS = file("/dev/null", 'a+') # 定义一个 outputS 文件对象
  # errorS = file("/dev/null", 'a+', 0) # 定义一个 errorS 文件对象
 
  # os.dup2(inputS.fileno(), sys.stdin.fileno()) # 把程序的输入流重定向到上面定义的 inputS 文件对象上。
  # os.dup2(so.fileno(), sys.stdout.fileno()) # 把程序的 输出流 重定向到上面定义的 outputS 文件对象上。
  # os.dup2(se.fileno(), sys.stderr.fileno()) # 把程序的 错误流 重定向到上面定义的 errorS 文件对象上。
 
  main() # main函数为真正程序逻辑代码
 
 
if __name__ == "__main__":
  if platform.system() == "Linux":
      createDaemon()
    else:
      sys.exit()
  
  

带控制参数的例子:

编写守护进程的基类,用于继承:


# 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

  编写自己的类:


 #导入刚刚编写的基类
 from daemon import Daemon
 #继承
 class MyTestDaemon(Daemon):
 #重写run方法,就是你要后台运行的函数
   def run(self):
   #后台运行的函数,比如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)

关于两次fork

第二个fork不是必须的,只是为了防止进程打开控制终端。

打开一个控制终端的条件是该进程必须是session leader。第一次fork,setsid之后,子进程成为session leader,进程可以打开终端;第二次fork产生的进程,不再是session leader,进程则无法打开终端。

也就是说,只要程序实现得好,控制程序不主动打开终端,无第二次fork亦可。

代码实现


# 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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python使用fork实现守护进程的方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python使用fork实现守护进程的方法

os模块中的fork方法可以创建一个子进程。相当于克隆了父进程 os.fork() 子进程运行时,os.fork方法会返回0;而父进程运行时,os.fork方法会返回子进程的PID号。 所以可以使用PID来区分两个进程:#!/usr/bin
2022-06-04

Python如何实现守护进程的方法示例

场景设置: 你编写了一个python服务程序,并且在命令行下启动,而你的命令行会话又被终端所控制,python服务成了终端程序的一个子进程。因此如果你关闭了终端,这个命令行程序也会随之关闭。要使你的python服务不受终端影响而常驻系统,就
2022-06-04

Python守护进程daemon实现

1.1 守护进程守护进程是系统中生存期较长的一种进程,常常在系统引导装入时启动,在系统关闭时终止,没有控制终端,在后台运行。守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。在
2023-01-31

python daemon守护进程实现

假如写一段服务端程序,如果ctrl+c退出或者关闭终端,那么服务端程序就会退出,于是就想着让这个程序成为守护进程,像httpd一样,一直在后端运行,不会受终端影响。 守护进程英文为daemon,像httpd,mysqld,最后一个字母d其实
2022-06-04

Python实现Daemon(守护)进程

最近在写Daemon进程,在编写过程中遇到一些小麻烦,最终还是解决了。我编写了两种,第一种是编写了一个程序,将其用setsid命令让其放入后台运行,第二种是直接fork()一个进程,在代码里将进程设置为后台启动。在os.sytem()函数其
2023-01-31

python中的daemon守护进程实现

守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。守护进程的特性1.在后台运行2.与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符、控制
2023-01-31

python守护进程监控子进程怎么实现

在Python中,可以使用multiprocessing模块来创建子进程并监控它们。具体实现方法如下:导入multiprocessing模块。import multiprocessing创建一个子进程的函数。def child_proces
2023-10-23

如何进行Python进程的守护进程实施

如何进行Python进程的守护进程实施,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Python进程这一计算机语言在实际的应用中,如果你在实际应用的过程中遇到相
2023-06-17

SAP ABAP守护进程的实现方式是什么

本篇文章给大家分享的是有关SAP ABAP守护进程的实现方式是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Linux系统很多服务都通过守护进程实现,常见的守护进程有系统日
2023-06-03

如何使linux shell实现守护进程脚本

这篇文章主要讲解了“如何使linux shell实现守护进程脚本”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使linux shell实现守护进程脚本”吧!#! /bin/sh#进程名字
2023-06-09

Java项目中实现守护线程的方法

Java项目中实现守护线程的方法?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线
2023-05-31

java多线程守护线程的实现方法是什么

本篇内容介绍了“java多线程守护线程的实现方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!lass StopThread impl
2023-06-04

用模板的方式创建守护进程代码实例

#include "wrap.h"#define MYDOMAIN_FLAG "/tmp/.mydomain_log" void domain_end(){ Unlink(MYDOMAIN_FLAG);} int domain_init()
2022-06-04

DaemonSet服务守护进程的使用场景是什么

这篇文章主要介绍“DaemonSet服务守护进程的使用场景是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“DaemonSet服务守护进程的使用场景是什么”文章能帮助大家解决问题。DaemonSe
2023-06-29

Linux中的进程守护supervisor安装配置及使用

supervisor是一个很好的守护程序管理工具,配置方面自动启动,日志输出,自动切割日志等等一系列强大功能,下面是在CentOS下安装使用supervisor的记录。 安装# epel源 yum install epel-release
2022-06-04

如何进行Java中守护线程的分析及使用

这篇文章跟大家分析一下“如何进行Java中守护线程的分析及使用”。内容详细易懂,对“如何进行Java中守护线程的分析及使用”感兴趣的朋友可以跟着小编的思路慢慢深入来阅读一下,希望阅读后能够对大家有所帮助。下面跟着小编一起深入学习“如何进行J
2023-06-26

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录