检查python脚本是否正在运行

Jos*_*unt 90 python daemon process

我有一个python守护程序作为我的Web应用程序的一部分运行/如果我的守护程序正在运行,我如何快速检查(使用python),如果没有,启动它?

我想以这种方式来修复守护进程的任何崩溃,因此脚本不必手动运行,它会在调用后立即自动运行然后保持运行.

如果我的脚本正在运行,我如何检查(使用python)?

ayc*_*dee 142

在Linux系统上使用的技术是使用域套接字:

import socket
import sys
import time

def get_lock(process_name):
    # Without holding a reference to our socket somewhere it gets garbage
    # collected when the function exits
    get_lock._lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)

    try:
        get_lock._lock_socket.bind('\0' + process_name)
        print 'I got the lock'
    except socket.error:
        print 'lock exists'
        sys.exit()


get_lock('running_test')
while True:
    time.sleep(3)
Run Code Online (Sandbox Code Playgroud)

它是原子的,并且避免了如果您的进程被发送SIGKILL而存在锁定文件的问题

您可以在文档中阅读socket.close这些套接字在收集垃圾时自动关闭.

  • 未来googlers的注意事项:此代码使用"抽象套接字",这是特定于Linux的(通常不是posix).更多相关信息:http://blog.eduardofleury.com/archives/2007/09/13 (18认同)
  • 我写这篇文章已经有一段时间......我的记忆很模糊.但我认为这是因为它收集了垃圾,否则套接字会被关闭.这样的事情. (7认同)
  • 空字节(`\ 0`)表示套接字是在抽象名称空间中创建的,而不是在文件系统本身上创建的. (7认同)
  • 这太棒了,它没有留下任何愚蠢的挥之不去的文件.希望我能更多地赞成这一点. (5认同)
  • 真棒.但我想知道为什么lock_socket定义为全局.我测试过,如果lock_socket没有定义为全局,则锁定系统在运行多个进程时不起作用.为什么?lock_socket已定义,仅用于get_lock函数.为什么必须在全球范围内定义? (4认同)
  • 抱歉,user443854,仅Linux。请参阅答案的第一句话。 (2认同)
  • 你可以这样做......但如果你想改变你的脚本名称怎么办?或者更重要的是,如果脚本的两个副本同时启动怎么办?我非常肯定,如果我把时机安排得恰到好处,我可以在没有意识到对方已经开始的情况下启动它们.这种锁文件机制是原子的.意味着它不能被两个不同的过程抓住. (2认同)

Dan*_*dey 88

在某处删除一个pidfile(例如/ tmp).然后,您可以通过检查文件中的PID是否存在来检查进程是否正在运行.完全关闭时不要忘记删除文件,并在启动时检查它.

#/usr/bin/env python

import os
import sys

pid = str(os.getpid())
pidfile = "/tmp/mydaemon.pid"

if os.path.isfile(pidfile):
    print "%s already exists, exiting" % pidfile
    sys.exit()
file(pidfile, 'w').write(pid)
try:
    # Do some actual work here
finally:
    os.unlink(pidfile)
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过检查/tmp/mydaemon.pid的内容是否为现有进程来检查进程是否正在运行.Monit(如上所述)可以为您完成此操作,或者您可以使用ps的返回代码编写一个简单的shell脚本来检查它.

ps up `cat /tmp/mydaemon.pid ` >/dev/null && echo "Running" || echo "Not running"
Run Code Online (Sandbox Code Playgroud)

为了额外的功劳,你可以使用atexit模块来确保你的程序在任何情况下(杀死,引发异常等)清理它的pid文件.

  • 对于那些现在发现这一点,请注意在python 3`file()`被删除,你应该使用`open()`.另外,即使你是2.7,你应该使用`open()`over`file()`,如下所述:https://docs.python.org/2/library/functions.html#file(是的,如果你使用python回到2.2左右,那么官方建议恰恰相反.显然他们改变了主意.) (10认同)
  • 虽然这是一个简单的解决方案,但它容易受到竞争条件的影 如果脚本的两个实例几乎同时执行,那么"如果os.path.isfile(pidfile)`可能会为两者评估为false,从而导致它们都写入锁定文件并继续运行". (7认同)
  • 如果程序中断,os.unlink()将不会执行,程序将不再运行,因为该文件存在.对 ? (6认同)
  • pid也被操作系统重用.所以误报是可能的. (6认同)
  • 正确,但这可能是预期的行为.如果pidfile存在但PID内部未运行,则表示非正常关闭,这意味着应用程序崩溃.这让你知道有问题,并检查日志.如上所述,atexit模块也可以处理这个问题,假设错误不在Python解释器本身中. (2认同)

Dec*_*cko 17

PID库可以做的正是这一点.

from pid import PidFile

with PidFile():
  do_something()
Run Code Online (Sandbox Code Playgroud)

它还将自动处理pidfile存在但进程未运行的情况.

  • @Jimmy你可以做例如`用PidFile(piddir ='/ home/user/run /')`来使用不同的目录将pid文件放在你有权限的地方.然后您不需要以root身份运行它 (8认同)

ojb*_*ass 10

在UNIX上有很好的重启进程包.有一个关于构建和配置它的精彩教程的是monit.通过一些调整,您可以拥有坚实可靠的技术来保持您的守护进程.


小智 10

当然Dan的例子不会像它应该的那样工作.

实际上,如果脚本崩溃,引发异常,或者不清除pid文件,脚本将多次运行.

我建议以下来自另一个网站:

这是为了检查是否已存在锁定文件

\#/usr/bin/env python
import os
import sys
if os.access(os.path.expanduser("~/.lockfile.vestibular.lock"), os.F_OK):
        #if the lockfile is already there then check the PID number
        #in the lock file
        pidfile = open(os.path.expanduser("~/.lockfile.vestibular.lock"), "r")
        pidfile.seek(0)
        old_pid = pidfile.readline()
        # Now we check the PID from lock file matches to the current
        # process PID
        if os.path.exists("/proc/%s" % old_pid):
                print "You already have an instance of the program running"
                print "It is running as process %s," % old_pid
                sys.exit(1)
        else:
                print "File is there but the program is not running"
                print "Removing lock file for the: %s as it can be there because of the program last time it was run" % old_pid
                os.remove(os.path.expanduser("~/.lockfile.vestibular.lock"))
Run Code Online (Sandbox Code Playgroud)

这是我们将PID文件放入锁定文件的代码的一部分

pidfile = open(os.path.expanduser("~/.lockfile.vestibular.lock"), "w")
pidfile.write("%s" % os.getpid())
pidfile.close()
Run Code Online (Sandbox Code Playgroud)

此代码将检查pid与现有运行进程相比的值,避免双重执行.

我希望它会有所帮助.

  • 应该使用`os.kill(old_pid,0)`,它应该在UNIX上更容易移植.如果没有这样的PID或它属于不同的用户,它将引发`OSError`. (3认同)
  • 请注意,使用 /proc/<pid> 检查进程是极其不可移植的,并且只能在 Linux 上可靠地工作。 (2认同)

Bob*_*toe 6

有无数的选择。一种方法是使用为您执行此类调用的系统调用或 python 库。另一种是简单地产生一个过程,如:

ps ax | grep processName
Run Code Online (Sandbox Code Playgroud)

并解析输出。很多人选择这种方法,在我看来这不一定是一种坏方法。


NST*_*NST 5

自己遇到了这个老问题,正在寻找解决方案。

使用psutil

import psutil
import sys
from subprocess import Popen

for process in psutil.process_iter():
    if process.cmdline() == ['python', 'your_script.py']:
        sys.exit('Process found: exiting.')

print('Process not found: starting it.')
Popen(['python', 'your_script.py'])
Run Code Online (Sandbox Code Playgroud)


kab*_*apy 5

我的解决方案是检查在Windows和ubuntu linux上测试过的进程和命令行参数

import psutil
import os

def is_running(script):
    for q in psutil.process_iter():
        if q.name().startswith('python'):
            if len(q.cmdline())>1 and script in q.cmdline()[1] and q.pid !=os.getpid():
                print("'{}' Process is already running".format(script))
                return True

    return False


if not is_running("test.py"):
    n = input("What is Your Name? ")
    print ("Hello " + n)
Run Code Online (Sandbox Code Playgroud)