簡體   English   中英

檢查腳本是否已經運行(python / linux)

[英]Checking if script is already running (python / linux)

我正在嘗試將 function 添加到腳本中以檢查它是否已在運行。 這是因為腳本將使用 cronjob 啟動。

這是我為 function 嘗試的內容的存根:

import psutil
import sys
import time


print(__file__)


def check_if_running():
    # print('process_nb: ', len(list(psutil.process_iter())))
    for i, q in enumerate(psutil.process_iter()):
        n = q.name() 
        # print(i, n)
        if 'python' in n:
            print(i, n)
            c = q.cmdline() 
            print(c)
            if __file__ in c:
                print('already running')
                sys.exit()
            else:
                print('not yet running')
                return 


if __name__ == '__main__':
    check_if_running()
    while True:
        time.sleep(3)

我第一次運行腳本,然后在單獨的 shell 中運行第二次。 第二次它應該打印'already running'並退出,但它沒有。

誰能幫我弄清楚為什么?

正如@JohnGordon 在評論中注意到的那樣,您的代碼中存在邏輯問題。

if __file__ in c:
    print('already running')
    sys.exit()
else:
    print('not yet running')
    return

在這里,如果它檢查一個進程並且它與文件不匹配,則 function 返回。 這意味着它不會檢查任何剩余的進程。

您只能在允許循環完成后推斷程序尚未運行。

def check_if_running():
    # print('process_nb: ', len(list(psutil.process_iter())))
    for i, q in enumerate(psutil.process_iter()):
        n = q.name() 
        # print(i, n)
        if 'python' in n.lower():
            print(i, n)
            c = q.cmdline() 
            print(c)
            if __file__ in c:
                print('already running')
                sys.exit()
    # every process has been checked
    print('not yet running')

我還將'python' in n'python' in n.lower() ,因為在我的系統上,該進程稱為'Python' ,而不是'python' ,並且此更改應涵蓋這兩種情況。

但是,當我嘗試這樣做時,我發現了另一個問題,即程序找到了自己的進程並總是關閉,即使它是它自己運行的唯一版本。

為避免這種情況,您可能想改為計算匹配進程的數量,並且僅在找到多個匹配項時才退出。

def count_processes(name, file):
    return sum(name in q.name().lower() and file in q.cmdline() for q in psutil.process_iter())

def check_if_running():
    if count_processes('python', __file__) > 1:
        print('already running')
        sys.exit()
    else:
        print('not yet running')

這是一個可能的替代方案 - 這個基於 Linux 文件鎖定的包裝器可以在您的 cron 作業的命令行開頭添加,然后您的腳本本身不需要檢查。

然后在 crontab 中,只需使用以下命令:

/path/to/lock_wrapper --abort /path/to/lock_file your_command [your_command_args...] 

確保鎖定文件位於本地文件系統上,以實現正確的文件鎖定功能。 (某些類型的共享文件系統不能可靠地使用文件鎖。)

如果文件已經被鎖定,那么它將中止。 如果沒有--abort ,它將等待。

#!/usr/bin/env python3

"""
   a wrapper to run a command with a lock file so that if multiple
   commands are invoked with the same lockfile, they will only run one
   at a time, i.e. when it's running it applies an exclusive lock to the
   lockfile, and if another process already has the exclusive lock then
   it has to wait for the other instance to release the lock before it
   starts to run, or optionally the second process will simply abort

   can be used for running instances of commands that are
   resource-intensive or will in some other way conflict with each
   other
"""

import sys
import os
import fcntl
import subprocess
from argparse import ArgumentParser


def parse_args():
    parser = ArgumentParser(__doc__)
    parser.add_argument(
        "-a", "--abort",
        action="store_true",
        help="abort if the lockfile is already locked (rather than waiting)")
    parser.add_argument("lockfile",
                        help=("path name of lockfile "
                              "(will be created if it does not exist)"))
    parser.add_argument("command",
                        nargs="*",
                        help="command (with any arguments)")
    return parser.parse_args()


def ensure_exists(filename):
    if not os.path.exists(filename):
        with open(filename, "w"):
            pass


def lock(fh, wait=True):
    if wait:
        fcntl.flock(fh, fcntl.LOCK_EX)
    else:
        try:
            fcntl.flock(fh, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError:
            sys.exit(1)


def unlock(fh):
    fcntl.flock(fh, fcntl.LOCK_UN)    


args = parse_args()
ensure_exists(args.lockfile)
with open(args.lockfile) as fh:
    lock(fh, wait=not args.abort)    
    with subprocess.Popen(args.command) as proc:
        return_code = proc.wait()
    unlock(fh)
sys.exit(return_code)

暫無
暫無

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

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