Python守护进程和脚本单例运行

Python 守护进程


守护进程简介

进程运行有时候需要脱离当前运行环境,尤其是Linux和Unix环境中需要脱离Terminal运行,这个时候就要用到守护进程。守护进程可以脱离当前环境要素来执行,这些要素包括:未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等

流程梳理

为了实现守护进程的功能,需要做以下几步:(1)fork一个新的进程,如果新的进程pid大于0,sys.exit(0),如果有异常,处理后退出即可;(2)脱离母体,切换到根目录下,设置os.umask(0)以便于获取高的读写权限。然后设置自己成为新的进程和回话组长,os.setsid();(3)然后尝试执行第二次fork进程,与第一步一致;(4)重定向标准文件描述符

函数实现


#!/usr/bin/env python
#coding: utf-8
import sys, os
 
'''将当前进程fork为一个守护进程
   注意:如果你的守护进程是由inet.d启动的,不要这样做!inet.d完成了
   所有需要做的事情,包括重定向标准文件描述符,需要做的事情只有chdir()和umask()了
'''
 
def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
     #重定向标准文件描述符(默认情况下定向到/dev/null)
    try: 
        pid = os.fork() 
          #父进程(会话组头领进程)退出,这意味着一个非会话组头领进程永远不能重新获得控制终端。
        if pid > 0:
            sys.exit(0)   #父进程退出
    except OSError, e: 
        sys.stderr.write ("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror) )
        sys.exit(1)
 
     #从母体环境脱离
    os.chdir("/")  #chdir确认进程不保持任何目录于使用状态,否则不能umount一个文件系统。也可以改变到对于守护程序运行重要的文件所在目录
    os.umask(0)    #调用umask(0)以便拥有对于写的任何东西的完全控制,因为有时不知道继承了什么样的umask。
    os.setsid()    #setsid调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。
 
     #执行第二次fork
    try: 
        pid = os.fork() 
        if pid > 0:
            sys.exit(0)   #第二个父进程退出
    except OSError, e: 
        sys.stderr.write ("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror) )
        sys.exit(1)
 
     #进程已经是守护进程了,重定向标准文件描述符
 
    for f in sys.stdout, sys.stderr: f.flush()
    si = open(stdin, 'r')
    so = open(stdout, 'a+')
    se = open(stderr, 'a+', 0)
    os.dup2(si.fileno(), sys.stdin.fileno())    #dup2函数原子化关闭和复制文件描述符
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

def main(): 
    do_something()
if __name__ == "__main__":
    daemonize()
    main()

单例脚本运行


原理

打开文件本身加锁,加一个排它锁,通过锁机制来保证单例运行。


#!/usr/bin/env python
#coding: utf-8
import fcntl, sys, time, os
pidfile = 0
 
def ApplicationInstance():
    global pidfile
    pidfile = open(os.path.realpath(__file__), "r")
    try:
        fcntl.flock(pidfile, fcntl.LOCK_EX | fcntl.LOCK_NB) #创建一个排他锁,并且所被锁住其他进程不会阻塞
    except:
        print "another instance is running..."
        sys.exit(1)
 
if __name__ == "__main__":
    ApplicationInstance()
    while True:
        print 'running...'
        time.sleep(1)

猜你喜欢

转载自www.cnblogs.com/KevinGeorge/p/9260145.html