Как убить процесс, который создается popen и использует connect ()? - PullRequest
1 голос
/ 10 августа 2011

У меня есть программа, P1, которую мне нужно запустить около 24 * 20000 раз с разными входами. Проблема в том, что P1 зависает, и я должен принудительно установить его вручную (kill). Моим первым решением было написание скрипта Python для вызова P1 и передача правильного ввода и получение вывода с использованием popen и communicate. Но из-за характера связи, которая ожидает вывода, я не могу убить процесс, пока он ожидает ответа. Я на Windows.

Я попытался использовать функцию multiprocess, но она только запускает P1 и не смогла отправить входные данные. Я с подозрением отношусь к тому, что я не использую каналы в popen, и немного попробовал, но, похоже, я не могу получить вывод от P1.

Есть идеи?

# This code run XLE and pass the intended input to it automatically
 def startExe(programPath, programArgStr):
 p = subprocess.Popen(programPath,stdout=subprocess.PIPE,stdin=subprocess.PIPE) p.stdin.write(programArgStr)
 p.communicate()[0]
# Need to kill the process if it takes longer than it should here

def main(folder): 
.. 
#loop
programArgStr = "create-parser"+path1+";cd "+ path2+"/s"+ command(counter) +";exit"

startExe(path, programArgStr)
..

Как вы можете видеть, может ли P1 успешно завершить заданную задачу, он может выйти сам, используя переданные ему команды выхода!

Ответы [ 4 ]

2 голосов
/ 10 августа 2011

Когда вы вызываете popen, вы можете указать либо канал, либо дескриптор файла, чтобы принимать стандартный вывод из процесса:

Popen (args, bufsize = 0, исполняемый файл = нет, stdin = нет, stdout = нет , stderr = нет, preexec_fn = нет, close_fds = False, оболочка = False, cwd = нет, env = Нет, universal_newlines = False, startupinfo = Нет, creationflags = 0)

Затем вы можете отслеживать файл / канал, который вы передаете popen, и, если ничего не написано, завершить процесс.

Более подробная информация о поп-аргах находится в документах Python .

Вместо того, чтобы использовать p.communicate, попробуйте выполнить цикл по строкам вывода:

while True:
    line = p.stdout.readline()
    if not line:
        break
    print ">>> " + line.rstrip()
2 голосов
/ 10 августа 2011

Если вам не нужно использовать Python, вы можете использовать Cygwin Bash вместе с командой timeout(1) для запуска команды с тайм-аутом. Тем не менее, поскольку реализация Cygwin fork() не очень быстра, и вы создаете огромное количество процессов, вам, вероятно, потребуются огромные накладные расходы только на создание процессов (я не знаю, является ли нативная версия Python для Windows лучше в этом отношении).

В качестве альтернативы, если у вас есть исходный код P1, почему бы вам просто не изменить его так, чтобы он мог выполнять несколько итераций того, что он делает за один вызов? Таким образом, вам не придется иметь дело с созданием и уничтожением 480 000 процессов, что будет иметь огромное значение, если объем работы, выполняемой каждым вызовом, невелик.

0 голосов
/ 29 сентября 2011

Я решил свою проблему, отредактировав текущий код и поместив код-убийцу в отдельный файл. для этого я добавляю строку для записи PID недавно созданного процесса в файл.

    #//Should come before p.commiunicate
    WriteStatus(str(p.pid) + "***" + str(gmtime().tm_hour) + "***" + str(gmtime().tm_min))        
    p.communicate()[0]

И монитор процессов выполняется отдельно и каждые 2 минуты проверяет, все ли процессы, перечисленные в файле, все еще активны. Если да, убейте их и удалите их удостоверение личности.

 def KillProcess(pid):

    subprocess.Popen("TASKKILL /PID "+ str(pid) + " /F /T" , shell=True)
    subprocess.Popen("TASKKILL /im WerFault.exe /F /T" , shell=True)
    print "kill"

    def ReadStatus(filePath):
    print "Checking" + filePath
    try:
            status = open(mainPath+filePath, 'r').readline()
    except:
            print "file removed" + filePath
            return 0
    if len(status) >0:
            info = status.split("***")                
            time = [gmtime().tm_hour, gmtime().tm_min]
            print time

            # Time deifferences
            difHour = time[0]- int(info[1])
            if difHour == 0: # in the same hour
                    difMin =  time[1]- int(info[2])
            else:
                    difMin = 60 - int(info[2]) + time[1]
            if difMin > 2:
                    try:
                            open(mainPath+filePath, 'w').write("")
                            KillProcess(info[0])
                    except:
                            pass
    return 1

  def monitor():
    # Read all the files
    listFiles = os.listdir(mainPath)
    while len(listFiles)>0:
            #GO and check the contents
            for file in listFiles:
                    #Open the file and Calculate if the process should be killed or not
                    pid = ReadStatus(file)
                    #Update listFiles due to remove of file after finishing the process '
                    # of each folder is done
                    listFiles = os.listdir(mainPath)
            for i in range(0,4):
                    time.sleep(30) #waits 30 sec
                    subprocess.Popen("TASKKILL /im WerFault.exe /F /T" , shell=True)
    #to indicate the job is done
    return 1
0 голосов
/ 10 августа 2011

Как насчет этого подхода?

from threading import Thread
def main(input):
    #your actual program, modified to take input as argument
queue = ['Your inputs stored here. Even better to make it to be a generator']
class Runner(Thread):
    def __init__(self):
        Thread.__init__(self)
    def run(self):
        while len(queue)>0:
            input = queue.pop()
            main(input)
        return True
#Use 24 threads
for thread in xrange(24):
    Runner().start()
#You may also join threads at the end.

Конечно, этот подход привел бы к некоторым уязвимостям, таким как «список очереди с двумя потоками одновременно», но я никогда не сталкивался с этим в реальной жизни.

...