如何使用pid在Python中终止进程?

67

我正在尝试编写一些Python代码,如果另一个Python代码没有启动,则会在子进程中启动它,否则终止终端和应用程序(Linux)。

所以它看起来像这样:

#!/usr/bin/python
from subprocess import Popen

text_file = open(".proc", "rb")
dat = text_file.read()
text_file.close()

def do(dat):

    text_file = open(".proc", "w")
    p = None

    if dat == "x" :

        p = Popen('python StripCore.py', shell=True)
        text_file.write( str( p.pid ) )

    else :
        text_file.write( "x" )

        p = # Assign process by pid / pid from int( dat )
        p.terminate()

    text_file.close()

do( dat )

我不知道如何通过进程ID为应用程序从文件“.proc”中读取名称。另一个问题是解释器说字符串“dat”不等于“x”? 我漏掉了什么?


4
你为什么要传递 shell=True 参数?据我所知,在你的使用情况下这是不必要的。另请注意,当使用 shell=True 时,p.pid 返回的进程 ID 不是 Python 进程的 PID,而是生成用于执行该进程的 shell 的 PID。 - Bakuriu
谢谢您的评论,但我认为它不太合适,因为我还需要关闭终端。 - Alex
3个回答

153

使用强大的psutil库非常简单:

p = psutil.Process(pid)
p.terminate()  #or p.kill()

如果您不想安装新的库,可以使用os模块:

import os
import signal

os.kill(pid, signal.SIGTERM) #or signal.SIGKILL 

还可以参考os.kill文档


如果你想要在程序没有运行时启动命令 python StripCore.py,或者关闭正在运行的程序,你可以使用psutil来实现。

例如:

import psutil
from subprocess import Popen

for process in psutil.process_iter():
    if process.cmdline() == ['python', 'StripCore.py']:
        print('Process found. Terminating it.')
        process.terminate()
        break
else:
    print('Process not found: starting it.')
    Popen(['python', 'StripCore.py'])

示例运行:

$python test_strip.py   #test_strip.py contains the code above
Process not found: starting it.
$python test_strip.py 
Process found. Terminating it.
$python test_strip.py 
Process not found: starting it.
$killall python
$python test_strip.py 
Process not found: starting it.
$python test_strip.py 
Process found. Terminating it.
$python test_strip.py 
Process not found: starting it.

注意: 在之前的psutil版本中, cmdline 是一个属性而不是一个方法。



谢谢,但对我来说主要问题是如何获取正在运行应用程序的pid? - Alex
5
@Alex你的意思是什么?你想终止正在执行的进程吗?那么只需使用sys.exit()即可。如果您想访问当前进程的pid,请使用os.getpid() - Bakuriu
请原谅我,@Bakuriu。我只是想编写一个脚本,如果某个应用程序没有启动,它将运行该应用程序。如果应用程序已经启动,则终止该应用程序和自身。 - Alex
1
@Alex 我已经使用 psutil 更新了我的问题,提供了一个干净的解决方案。如果你想要,你甚至可以只使用标准库来实现,但这样会不太可靠(例如,你将 pid 保存到文件中。另一个进程杀死了你的 StripCore.py 脚本并启动了一个新进程,该进程被分配给新的 pid:你如何知道同一 pid 现在不再指向正在运行的脚本?这不是 psutil 的问题,因为你可以检查 cmdline 属性),而且更加复杂。 - Bakuriu
我认为你的意思是 signal.SIGTERM,而不是 signal.SIGQUITsigquit 是一个由键盘发出的事件。 - ThorSummoner
显示剩余3条评论

4

我想做与此相同的事情,但我希望在一个文件中完成。

所以逻辑应该是:

  • 如果正在运行我的名字的脚本,请终止它,然后退出
  • 如果没有运行我的名字的脚本,则执行操作

我修改了Bakuriu的答案,并得出了以下结果:

from os import getpid
from sys import argv, exit
import psutil  ## pip install psutil

myname = argv[0]
mypid = getpid()
for process in psutil.process_iter():
    if process.pid != mypid:
        for path in process.cmdline():
            if myname in path:
                print "process found"
                process.terminate()
                exit()

## your program starts here...

运行该脚本会执行脚本的功能。运行另一个脚本实例将会结束任何正在运行的脚本实例。
我使用它来显示一个小的PyGTK日历小部件,点击时即可运行。如果我点击时日历未弹出,它就会显示。如果日历正在运行,我再次点击时,它就会消失。

0

所以,虽然与此不直接相关,但这是在尝试使用Python终止从特定文件夹运行的进程时首先出现的问题。

它还用一种方式回答了问题(即使这是一个旧问题,有很多答案)。

在创建一种更快捷的方式来爬取一些政府网站的数据时,我遇到了一个问题,如果池中的任何一个进程卡住了,它们将被跳过,但仍会占用我的计算机内存。这就是我使用的杀死它们的解决方案,如果有人知道更好的方法,请告诉我!

import pandas as pd
import wmi
from re import escape
import os

def kill_process(kill_path, execs):
    f = wmi.WMI()
    esc = escape(kill_path)
    temp = {'id':[], 'path':[], 'name':[]}
    for process in f.Win32_Process():
        temp['id'].append(process.ProcessId)
        temp['path'].append(process.ExecutablePath)
        temp['name'].append(process.Name)
    temp = pd.DataFrame(temp)
    temp = temp.dropna(subset=['path']).reset_index().drop(columns=['index'])
    temp = temp.loc[temp['path'].str.contains(esc)].loc[temp.name.isin(execs)].reset_index().drop(columns=['index'])
    [os.system('taskkill /PID {} /f'.format(t)) for t in temp['id']]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接