简体   繁体   English

检查 python 脚本是否正在运行

[英]Check to see if python script is running

I have a python daemon running as a part of my web app/ How can I quickly check (using python) if my daemon is running and, if not, launch it?我有一个 python 守护程序作为我的 web 应用程序的一部分运行/如何快速检查(使用 python)我的守护程序是否正在运行,如果没有,启动它?

I want to do it that way to fix any crashes of the daemon, and so the script does not have to be run manually, it will automatically run as soon as it is called and then stay running.我想这样做以修复守护程序的任何崩溃,因此脚本不必手动运行,它会在调用后立即自动运行,然后继续运行。

How can i check (using python) if my script is running?如果我的脚本正在运行,我如何检查(使用 python)?

A technique that is handy on a Linux system is using domain sockets:在 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:
        # The null byte (\0) means the socket is created 
        # in the abstract namespace instead of being created 
        # on the file system itself.
        # Works only in Linux
        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)

It is atomic and avoids the problem of having lock files lying around if your process gets sent a SIGKILL它是原子的,如果您的进程收到 SIGKILL,它可以避免出现锁定文件的问题

You can read in the documentation for socket.close that sockets are automatically closed when garbage collected.您可以socket.close的文档中阅读垃圾收集时套接字会自动关闭。

Drop a pidfile somewhere (eg /tmp).将 pidfile 放在某处(例如 /tmp)。 Then you can check to see if the process is running by checking to see if the PID in the file exists.然后你可以通过检查文件中的PID是否存在来检查进程是否正在运行。 Don't forget to delete the file when you shut down cleanly, and check for it when you start up.不要忘记在干净地关闭时删除该文件,并在启动时检查它。

#/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)

Then you can check to see if the process is running by checking to see if the contents of /tmp/mydaemon.pid are an existing process.然后,您可以通过检查 /tmp/mydaemon.pid 的内容是否为现有进程来检查进程是否正在运行。 Monit (mentioned above) can do this for you, or you can write a simple shell script to check it for you using the return code from ps. Monit(上面提到的)可以为你做这件事,或者你可以编写一个简单的 shell 脚本来使用 ps 的返回码来检查它。

ps up `cat /tmp/mydaemon.pid ` >/dev/null && echo "Running" || echo "Not running"

For extra credit, you can use the atexit module to ensure that your program cleans up its pidfile under any circumstances (when killed, exceptions raised, etc.).作为额外的功劳,您可以使用 atexit 模块来确保您的程序在任何情况下(被杀死、引发异常等)都会清理其 pidfile。

The pid library can do exactly this. pid库可以做到这一点。

from pid import PidFile

with PidFile():
  do_something()

It will also automatically handle the case where the pidfile exists but the process is not running.它还会自动处理 pidfile 存在但进程未运行的情况。

Of course the example from Dan will not work as it should be.当然,来自 Dan 的例子不会像它应该的那样工作。

Indeed, if the script crash, rise an exception, or does not clean pid file, the script will be run multiple times.确实,如果脚本崩溃、出现异常或不清除 pid 文件,脚本将多次运行。

I suggest the following based from another website:我建议基于另一个网站的以下内容:

This is to check if there is already a lock file existing这是为了检查是否已经存在锁定文件

\#/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"))

This is part of code where we put a PID file in the lock file这是我们将 PID 文件放在锁定文件中的代码的一部分

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

This code will check the value of pid compared to existing running process., avoiding double execution.此代码将检查与现有正在运行的进程相比的 pid 值,避免双重执行。

I hope it will help.我希望它会有所帮助。

There are very good packages for restarting processes on UNIX.在 UNIX 上有非常好的重新启动进程的包。 One that has a great tutorial about building and configuring it is monit .有一个关于构建和配置它的很棒的教程是monit With some tweaking you can have a rock solid proven technology keeping up your daemon.通过一些调整,您可以获得坚如磐石的成熟技术来保持您的守护进程。

My solution is to check for the process and command line arguments Tested on windows and ubuntu linux我的解决方案是检查在 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)

Came across this old question looking for solution myself.自己遇到了这个老问题,正在寻找解决方案。

Use psutil :使用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'])

There are a myriad of options.有无数的选择。 One method is using system calls or python libraries that perform such calls for you.一种方法是使用为您执行此类调用的系统调用或 python 库。 The other is simply to spawn out a process like:另一种是简单地产生一个过程,如:

ps ax | grep processName

and parse the output.并解析输出。 Many people choose this approach, it isn't necessarily a bad approach in my view.很多人选择这种方法,在我看来这不一定是一种坏方法。

Try this other version试试这个其他版本

def checkPidRunning(pid):        
    '''Check For the existence of a unix pid.
    '''
    try:
        os.kill(pid, 0)
    except OSError:
        return False
    else:
        return True

# Entry point
if __name__ == '__main__':
    pid = str(os.getpid())
    pidfile = os.path.join("/", "tmp", __program__+".pid")

    if os.path.isfile(pidfile) and checkPidRunning(int(file(pidfile,'r').readlines()[0])):
            print "%s already exists, exiting" % pidfile
            sys.exit()
    else:
        file(pidfile, 'w').write(pid)

    # Do some actual work here
    main()

    os.unlink(pidfile)

I'm a big fan of Supervisor for managing daemons.我是Supervisor管理守护进程的忠实粉丝。 It's written in Python, so there are plenty of examples of how to interact with or extend it from Python.它是用 Python 编写的,因此有很多关于如何与 Python 交互或从 Python 扩展它的示例。 For your purposes the XML-RPC process control API should work nicely.出于您的目的, XML-RPC 过程控制 API应该可以很好地工作。

与其开发你自己的 PID 文件解决方案(它比你想象的有更多的微妙之处和极端情况),不如看看supervisord——这是一个过程控制系统,它可以很容易地围绕现有的 Python 包装作业控制和守护进程行为脚本。

其他答案对于 cron 作业之类的事情非常有用,但是如果您正在运行守护程序,则应该使用daemontools 之类的东西来监视它。

ps ax | grep processName

如果 pycharm 中的调试脚本总是退出

pydevd.py --multiproc --client 127.0.0.1 --port 33882 --file processName

try this:尝试这个:

#/usr/bin/env python
import os, sys, atexit

try:
    # Set PID file
    def set_pid_file():
        pid = str(os.getpid())
        f = open('myCode.pid', 'w')
        f.write(pid)
        f.close()

    def goodby():
        pid = str('myCode.pid')
        os.remove(pid)

    atexit.register(goodby)
    set_pid_file()
    # Place your code here

except KeyboardInterrupt:
    sys.exit(0)

Here is more useful code (with checking if exactly python executes the script):这是更有用的代码(检查python是否确实执行了脚本):

#! /usr/bin/env python

import os
from sys import exit


def checkPidRunning(pid):
    global script_name
    if pid<1:
        print "Incorrect pid number!"
        exit()
    try:
        os.kill(pid, 0)
    except OSError:
        print "Abnormal termination of previous process."
        return False
    else:
        ps_command = "ps -o command= %s | grep -Eq 'python .*/%s'" % (pid,script_name)
        process_exist = os.system(ps_command)
        if process_exist == 0:
            return True
        else:
            print "Process with pid %s is not a Python process. Continue..." % pid
            return False


if __name__ == '__main__':
    script_name = os.path.basename(__file__)
    pid = str(os.getpid())
    pidfile = os.path.join("/", "tmp/", script_name+".pid")
    if os.path.isfile(pidfile):
        print "Warning! Pid file %s existing. Checking for process..." % pidfile
        r_pid = int(file(pidfile,'r').readlines()[0])
        if checkPidRunning(r_pid):
            print "Python process with pid = %s is already running. Exit!" % r_pid
            exit()
        else:
            file(pidfile, 'w').write(pid)
    else:
        file(pidfile, 'w').write(pid)

# main programm
....
....

os.unlink(pidfile)

Here is string:这是字符串:

ps_command = "ps -o command= %s | grep -Eq 'python .*/%s'" % (pid,script_name)

returns 0 if "grep" is successful, and the process "python" is currently running with the name of your script as a parameter .如果“grep”成功,则返回 0,并且进程“python”当前正在以您的脚本名称作为参数运行。

A simple example if you only are looking for a process name exist or not:一个简单的例子,如果你只是在寻找一个进程名称是否存在:

import os

def pname_exists(inp):
    os.system('ps -ef > /tmp/psef')
    lines=open('/tmp/psef', 'r').read().split('\n')
    res=[i for i in lines if inp in i]
    return True if res else False

Result:
In [21]: pname_exists('syslog')
Out[21]: True

In [22]: pname_exists('syslog_')
Out[22]: False

I was looking for an answer on this and in my case, came to mind a very easy and very good solution, in my opinion (since it's not possible to exist a false positive on this, I guess - how can the timestamp on the TXT be updated if the program doesn't do it):我一直在寻找有关此问题的答案,在我看来,我想到了一个非常简单且非常好的解决方案(因为我猜不可能对此存在误报 - TXT 上的时间戳如何如果程序不这样做,则更新):

--> just keep writing on a TXT the current timestamp in some time interval, depending on your needs (here each half hour was perfect). --> 只需根据您的需要,在某个时间间隔内继续在 TXT 上写入当前时间戳(这里每半小时是完美的)。

If the timestamp on the TXT is outdated relatively to the current one when you check, then there was a problem on the program and it should be restarted or what you prefer to do.如果您检查时 TXT 上的时间戳相对于当前时间戳已过时,则说明程序存在问题,应重新启动它或您更喜欢做什么。

A portable solution that relies on multiprocessing.shared_memory :一个依赖于multiprocessing.shared_memory的可移植解决方案:

import atexit
from multiprocessing import shared_memory

_ensure_single_process_store = {}


def ensure_single_process(name: str):
    if name in _ensure_single_process_store:
        return
    try:
        shm = shared_memory.SharedMemory(name='ensure_single_process__' + name,
                                         create=True,
                                         size=1)
    except FileExistsError:
        print(f"{name} is already running!")
        raise
    _ensure_single_process_store[name] = shm
    atexit.register(shm.unlink)

Usually you wouldn't have to use atexit , but sometimes it helps to clean up upon abnormal exit.通常您不必使用atexit ,但有时它有助于在异常退出时进行清理。

Consider the following example to solve your problem:考虑以下示例来解决您的问题:

#!/usr/bin/python
# -*- coding: latin-1 -*-

import os, sys, time, signal

def termination_handler (signum,frame):
    global running
    global pidfile
    print 'You have requested to terminate the application...'
    sys.stdout.flush()
    running = 0
    os.unlink(pidfile)

running = 1
signal.signal(signal.SIGINT,termination_handler)

pid = str(os.getpid())
pidfile = '/tmp/'+os.path.basename(__file__).split('.')[0]+'.pid'

if os.path.isfile(pidfile):
    print "%s already exists, exiting" % pidfile
    sys.exit()
else:
    file(pidfile, 'w').write(pid)

# Do some actual work here

while running:
  time.sleep(10)

I suggest this script because it can be executed one time only.我建议使用这个脚本,因为它只能执行一次。

Using bash to look for a process with the current script's name.使用 bash 查找具有当前脚本名称的进程。 No extra file.没有额外的文件。

import commands
import os
import time
import sys

def stop_if_already_running():
    script_name = os.path.basename(__file__)
    l = commands.getstatusoutput("ps aux | grep -e '%s' | grep -v grep | awk '{print $2}'| awk '{print $2}'" % script_name)
    if l[1]:
        sys.exit(0);

To test, add要测试,添加

stop_if_already_running()
print "running normally"
while True:
    time.sleep(3)

This is what I use in Linux to avoid starting a script if already running:这是我在 Linux 中用来避免在已经运行的情况下启动脚本的方法:

import os
import sys


script_name = os.path.basename(__file__)
pidfile = os.path.join("/tmp", os.path.splitext(script_name)[0]) + ".pid"


def create_pidfile():
    if os.path.exists(pidfile):
        with open(pidfile, "r") as _file:
            last_pid = int(_file.read())

        # Checking if process is still running
        last_process_cmdline = "/proc/%d/cmdline" % last_pid
        if os.path.exists(last_process_cmdline):
            with open(last_process_cmdline, "r") as _file:
                cmdline = _file.read()
            if script_name in cmdline:
                raise Exception("Script already running...")

    with open(pidfile, "w") as _file:
        pid = str(os.getpid())
        _file.write(pid)


def main():
    """Your application logic goes here"""


if __name__ == "__main__":
    create_pidfile()
    main()

This approach works good without any dependency on an external module.这种方法在不依赖任何外部模块的情况下效果很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM