当另一个 python 脚本正在运行时,如何停止我的 python 脚本?

Posted

技术标签:

【中文标题】当另一个 python 脚本正在运行时,如何停止我的 python 脚本?【英文标题】:How can I stop my python script when another python script is running? 【发布时间】:2015-06-03 23:28:17 【问题描述】:

我想知道如何在当前 python 脚本已经运行时停止它。

为了清楚起见,我想用我自己的 python 脚本编写它。所以第一件事,在 main 方法中,它会检查我的 python 脚本是否已经在运行。如果它正在运行,我想退出并显示错误消息。

目前我正在尝试这段代码:

if os.system("ps ax | grep sample_python.py") == True:
     print "fail"
     exit(0)
else:
     print "pass"

上面的代码看起来像是在 grepping python 名称.. 但它总是进入 else 循环而不是进入 if 循环并退出..

因此,出于测试目的,我运行我的脚本并在另一个终端上再次运行我的脚本。第一个脚本不会停止,但第二个 python 不会进入 if 循环以打印出错误消息。

我该如何解决这个问题?


好吧,我发现了一个愚蠢的东西,我想看看是否有人可以帮助我解决它.. 所以我的意思是如果另一个python正在运行,就杀死刚刚启动的python.. 但愚蠢的是..因为我正在运行我的python并在这个python内部运行一个检查编码..它总是会退出..因为一旦我启动python PID就会被创建并运行......

所以.. python 启动-> pid 创建并运行-> 检查 python 是否正在运行-> 是 python 正在运行-> 退出。

我想看看有没有办法 python 启动 -> 检查 python 是否已经在运行 -> 如果它正在运行,杀死当前的 python 而不是正在运行的那个。

【问题讨论】:

如果找不到匹配项,grep 会找到自己 诊断您出现的问题的方法是首先在命令行中输入ps ax ...,无论是在您的脚本运行时还是在不检查您是否有正确的命令行时。然后你编写一个 python 脚本,它只打印os.system( ... 调用的结果,在这两种情况下再次检查是否存在差异。然后你应该可以编写你需要的脚本了。 您可以使用 pgreppkill 来查找和终止进程,而不包括 grep 进程本身(还有各种 shell 实用程序可以确保只有一个副本正在运行,尽管它们可能不会适合您的情况) 我认为它也可能失败,因为当我执行ps | grep progname 时,列出的进程之一是 grep 命令。并且包含了 grep 的命令行参数“progname”。这可能取决于操作系统。 【参考方案1】:

带有正在运行进程的 PID 的 lockfile 是一种更系统的方法。程序只是在开始时检查一个 PID 文件是否既存在又被锁定(flock 或lockf);如果是这样,则意味着该程序的另一个实例仍在运行。如果没有,它会创建(或重写)PID 文件并锁定它。

flock/lockf 锁的优点是操作系统会在程序终止的情况下自动解除锁。

在此处查看如何在 Python 中执行此操作:

Python: module for creating PID-based lockfile?

【讨论】:

仅供参考,已接受答案中链接的脚本自编写答案以来已更新,并且对 Mercurial 包的依赖性比最初更大。不过,这对 OP 来说可能不是问题。 是的 - PID 是这方面的首选标准。另见***.com/questions/688343/…【参考方案2】:

为什么不使用grep,而不是创建一个锁定文件?您的程序的一个实例在已知位置创建一个文件,并在退出时将其删除。任何其他实例都必须检查该文件是否存在,并且只有在它已经存在时才应继续运行。

os.open() 函数对此有特定的标志:

import os

LOCKFILE_LOCATION = "/path/to/lockfile"

try:
    os.open(LOCKFILE_LOCATION, os.O_CREAT|os.O_WRONLY|os.O_EXCL)
    # Maybe even write the script's PID to this file, just in case you need
    # to check whether the program died unexpectedly.
except OSError:
    # File exists or could not be created. Can check errno if you really
    # need to know, but this may be OS dependent.
    print("Failed to create lockfile. Is another instance already running?")
    exit(1)
else:
    print("Pass")
    # Run the rest of the program.
    # Delete the file
    os.remove(LOCKFILE_LOCATION)

通过在 `print("Pass") 之后放置 import time; time.sleep(20) 并运行此脚本的多个实例来尝试一下;除了一个之外,其他人都应该失败。

【讨论】:

【参考方案3】:

更多pythonic方式:

import os
import psutil

script_name = os.path.basename(__file__)
if script_name in [p.name() for p in psutil.get_process_list()]:
   print "Running"

【讨论】:

psutil.get_process_list() 在 2012 年被弃用。source 现在的 Python 方式是使用可迭代对象。【参考方案4】:

os.system() 返回已运行命令的退出值。如果 ps 成功,则返回 0,不等于 True。您可以显式测试该命令是否返回零,这应该会带您进入 if 块。

编辑:为此需要os.subprocess。这四个命令应该可以得到你想要的。

p1 = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['grep', 'bash'], stdin=p1.stdout, stdout=subprocess.PIPE)
p3 = subprocess.Popen(['wc', '-l'], stdin=p2.stdout, stdout=subprocess.PIPE)
count = int(p3.stdout.read())
if count > 1:
    print('yes')

将“bash”替换为您的脚本名称。它的作用是获取正在运行的进程列表、输出到 grep 的管道以筛选除您的脚本(或代码示例中的 bash 实例)之外的所有进程、输出到 wc 以获取行数的管道,然后询问该进程它的标准输出是当前正在运行的脚本实例的计数。然后,您可以在 if 语句中使用该计数变量,如果有多个实例正在运行,您可以中止运行。

【讨论】:

谢谢,但我现在遇到了一个问题.. 当我运行我的编码if os.system("ps ax | grep sample_python.py").. 它总是打印 ` 5440 pts/0 S+ 0:00 sh -c ps ax | grep sample_python.py` 和 5442 pts/0 S+ 0:00 grep sample_python.py 并立即退出.. 即使我的 python 没有运行或刚刚启动.. ` 如果两个脚本名称相同,就像听起来一样,那么 ps/grep 将始终返回至少一行。因此,您可以通过 wc 运行 grep 的输出以查看是否有两行或更多行。另一种方法是创建一个锁定文件,该文件在脚本运行结束时被删除 - 然后您可以测试它是否存在,如果不存在,则创建它并运行脚本。 我不明白..你能解释一下吗? 如果我理解这个问题,你想启动一个脚本,它的第一个动作是检测是否有相同脚本的另一个副本正在运行。系统调用将始终至少找到当前脚本本身。但是如果另一个副本正在运行,它应该检测到两个进程。 wc -l 计算行数,因此您可以测试是否有两行或更多行。那是你要问的部分吗? 是的,这正是我想要做的......但现在......我怎样才能改变我的编码来做到这一点?【参考方案5】:

您可以使用跨平台库psutil 来迭代进程,解析每个进程的命令行并检查它是否是具有相同脚本路径的python 进程,然后您可以在只找到一个时停止执行杀死/停止旧实例并继续使用新实例。

import os
import psutil
import sys

for proc in psutil.process_iter():
    if "python" in proc.name():
        if len(proc.cmdline()) > 1:
            script_path = sys.argv[0]
            proc_script_path = proc.cmdline()[1]
            if script_path.startswith("." + os.sep) or script_path.startswith(".." + os.sep):
                script_path = os.path.normpath(os.path.join(os.getcwd(), script_path))
            if proc_script_path.startswith("." + os.sep) or proc_script_path.startswith(".." + os.sep):
                proc_script_path = os.path.normpath(os.path.join(proc.cwd(), proc_script_path))
            if  script_path == proc_script_path and os.getpid() != proc.pid:
                #proc.kill() # you can terminate all the other instances
                sys.exit() # or your way, terminate this newer instance here

【讨论】:

【参考方案6】:

因为 os.system("ps ax | grep sample_python.py") 返回 0。这是不正确的。

看看这个问题: Assign output of os.system to a variable and prevent it from being displayed on the screen

你必须写

os.popen('cat /etc/services').read() 

但是这样你总是会进入“失败”,因为你的脚本已经开始了。您必须计算返回的行数...

将这里视为单个实例的变体:

Python: single instance of program

我写了这样的脚本。我在开始时创建了一个具有任何名称的文件,并在最后删除。这是守护程序脚本。开始时我检查了该文件是否存在。

不错的变种在这里Ensure a single instance of an application in Linux:

import fcntl
pid_file = 'program.pid'
fp = open(pid_file, 'w')
try:
    fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    # another instance is running
    sys.exit(1)

【讨论】:

以上是关于当另一个 python 脚本正在运行时,如何停止我的 python 脚本?的主要内容,如果未能解决你的问题,请参考以下文章

当另一个孩子完成时如何退出一个子进程

当另一个文本框在报告中增加其大小时如何停止增加文本框的大小

当另一个正在运行时,如何暂停一个倒数计时器?

HTML5 - 当另一个音频标签开始播放时如何停止音频?

如何停止运行没有 GUI 窗口的 Python .pyw 脚本?

当另一个 UIScrollView 滚动时停止动画 UIScrollView