簡體   English   中英

檢查 python 腳本是否正在運行

[英]Check to see if python script is running

我有一個 python 守護程序作為我的 web 應用程序的一部分運行/如何快速檢查(使用 python)我的守護程序是否正在運行,如果沒有,啟動它?

我想這樣做以修復守護程序的任何崩潰,因此腳本不必手動運行,它會在調用后立即自動運行,然后繼續運行。

如果我的腳本正在運行,我如何檢查(使用 python)?

在 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)

它是原子的,如果您的進程收到 SIGKILL,它可以避免出現鎖定文件的問題

您可以socket.close的文檔中閱讀垃圾收集時套接字會自動關閉。

將 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)

然后,您可以通過檢查 /tmp/mydaemon.pid 的內容是否為現有進程來檢查進程是否正在運行。 Monit(上面提到的)可以為你做這件事,或者你可以編寫一個簡單的 shell 腳本來使用 ps 的返回碼來檢查它。

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

作為額外的功勞,您可以使用 atexit 模塊來確保您的程序在任何情況下(被殺死、引發異常等)都會清理其 pidfile。

pid庫可以做到這一點。

from pid import PidFile

with PidFile():
  do_something()

它還會自動處理 pidfile 存在但進程未運行的情況。

當然,來自 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"))

這是我們將 PID 文件放在鎖定文件中的代碼的一部分

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

此代碼將檢查與現有正在運行的進程相比的 pid 值,避免雙重執行。

我希望它會有所幫助。

在 UNIX 上有非常好的重新啟動進程的包。 有一個關於構建和配置它的很棒的教程是monit 通過一些調整,您可以獲得堅如磐石的成熟技術來保持您的守護進程。

我的解決方案是檢查在 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)

自己遇到了這個老問題,正在尋找解決方案。

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

有無數的選擇。 一種方法是使用為您執行此類調用的系統調用或 python 庫。 另一種是簡單地產生一個過程,如:

ps ax | grep processName

並解析輸出。 很多人選擇這種方法,在我看來這不一定是一種壞方法。

試試這個其他版本

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)

我是Supervisor管理守護進程的忠實粉絲。 它是用 Python 編寫的,因此有很多關於如何與 Python 交互或從 Python 擴展它的示例。 出於您的目的, 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

嘗試這個:

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

這是更有用的代碼(檢查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)

這是字符串:

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

如果“grep”成功,則返回 0,並且進程“python”當前正在以您的腳本名稱作為參數運行。

一個簡單的例子,如果你只是在尋找一個進程名稱是否存在:

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

我一直在尋找有關此問題的答案,在我看來,我想到了一個非常簡單且非常好的解決方案(因為我猜不可能對此存在誤報 - TXT 上的時間戳如何如果程序不這樣做,則更新):

--> 只需根據您的需要,在某個時間間隔內繼續在 TXT 上寫入當前時間戳(這里每半小時是完美的)。

如果您檢查時 TXT 上的時間戳相對於當前時間戳已過時,則說明程序存在問題,應重新啟動它或您更喜歡做什么。

一個依賴於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)

通常您不必使用atexit ,但有時它有助於在異常退出時進行清理。

考慮以下示例來解決您的問題:

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

我建議使用這個腳本,因為它只能執行一次。

使用 bash 查找具有當前腳本名稱的進程。 沒有額外的文件。

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);

要測試,添加

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

這是我在 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()

這種方法在不依賴任何外部模塊的情況下效果很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM