Открытие терминала gnome в Python сразу выглядит как зомбиPython

Программы на Python
Anonymous
Открытие терминала gnome в Python сразу выглядит как зомби

Сообщение Anonymous »

Для справки: я работаю над сценарием для обучения нескольких моделей Pytorch. У меня есть сценарий обучения, который я хочу запустить как подпроцесс в терминале gnome. Основная причина этого в том, что я могу следить за прогрессом тренировок. В тех случаях, когда у меня может быть несколько графических процессоров, я хотел бы запустить сценарий обучения несколько раз в разных окнах. Для этого я использовал popen. Следующий код позволяет открыть новое окно терминала и запустить сценарий обучения

Код: Выделить всё

#create a list of commands
commands = []
kd_cfg = KDConfig.read(kd_cfg_path)
cmd = "python scripts/train_torch.py "
for specialist in kd_cfg.specialists:
cmd += f"--config {kd_cfg.runtime_dict['specialists'][specialist]['config']} "
...

# Run each command in a new terminal and store the process object
num_gpus = len(gpus)
free_gpus = copy.deepcopy(gpus)
processes = []
worker_sema = threading.Semaphore(num_gpus)
commands_done = [False for _ in range(len(commands))]

#start the watchdog
watch = threading.Thread(target=watch_dog, args=(processes,free_gpus,commands_done,worker_sema))
watch.start()

for cmd_idx, command in enumerate(commands):

worker_sema.acquire()

gpu = free_gpus.pop()
command += f" --gpu {gpu}" #allocate a free GPU from the list
split_cmd_arr = shlex.split(command)
proc = subprocess.Popen(['gnome-terminal', '--'] + split_cmd_arr)

processes.append( (cmd_idx,gpu,proc) )

Часть, на которой я застрял, — это управление параллелизмом. Чтобы защитить ресурс графического процессора, я использую семафор. Мой план состоял в том, чтобы следить за процессом запуска терминала GNOME и по его завершению выпустить семафор, чтобы начать следующий процесс обучения. Вместо этого происходит то, что все команды выполняются одновременно. Когда я тестирую две команды и ограничиваюсь одним графическим процессором, я все равно вижу два открытых терминала и начнутся два обучения. В приведенном ниже коде потока сторожевого таймера я вижу, что оба процесса являются зомби и не имеют дочерних элементов, даже ПОКА я наблюдаю, как цикл обучения выполняется внутри обоих терминалов без сбоев.

Код: Выделить всё

   # Check if processes are still running
while not all(commands_done):
for cmd_idx, gpu, proc in processes:
# try:
# Check if process is still running
ps_proc = psutil.Process(proc.pid)

#BC we call bash python out of the gate it executes as a child proc
ps_proc_children = get_child_processes(proc.pid)
proc_has_running_children = any(child.is_running for child in ps_proc_children)

print(f"status: {ps_proc.status()}")
print(f"children:  {ps_proc_children}")
if proc_has_running_children:
print(f"Process {proc.pid} on GPU {gpu} is still running", end='\r')
else:
print(f"Process {proc.pid} has terminated")
free_gpus.append(gpu)
commands_done[cmd_idx] = True
processes.remove((cmd_idx, gpu, proc))

ps_proc.wait()
print(f"removed proc {ps_proc.pid}")
worker_sema.release()
Я подумал, что, возможно, подпроцесс запускает другой процесс, а затем сразу же возвращается, но я удивлен, увидев, что дочерних процессов тоже нет. Если у кого-то есть какие-либо идеи, мы будем очень признательны.
Если это поможет, вот пример вывода сторожевого таймера.

Код: Выделить всё

status: zombie
children:  []
Process 4076 has terminated
removed proc 4076
status: zombie
children:  []
Process 4133 has terminated
removed proc 4133

/////////////////////РЕДАКТИРОВАНИЕ///////////////// ///////////////
Мне еще предстоит найти способ напрямую получить PID процессов через интерфейс POPEN. У меня есть обходной путь, но я все еще думаю, что должен быть более чистый способ сделать это.
Я воспользовался функцией ps_utilprocess_iter. Я перебираю все запущенные процессы, просматриваю команды и выполняю сопоставление регулярных выражений, чтобы найти соответствующую команду. Передается достаточно уникальных вещей, таких как номер графического процессора и строка даты и времени, поэтому маловероятно, что эти две вещи совпадут [но это серьезный недостаток подхода]

Код: Выделить всё

def get_pid_for_unique_cmd(cmdl_string2find):

pid = None
for pp in psutil.process_iter(attrs=['pid', 'name', 'cmdline']):

cmdl_cmd = ""
if pp.info["cmdline"]:
cmdl_cmd = ' '.join(pp.info['cmdline'])

#if there is not single space in the typed command it gets mad so need to strip
if "".join(cmdl_cmd.split()) == "".join(cmdl_string2find.split()):

pid = pp.pid
print(f"found process {pid} that matches {cmdl_string2find}")
print(pp.info)
ps_proc = psutil.Process(pid)
print(f"status {ps_proc.status()}")
print()

return pid
Затем я передаю этот pid в поток сторожевого таймера, где я обновил все, чтобы проверить этот pid вместо использования объекта proc.

Подробнее здесь: https://stackoverflow.com/questions/787 ... s-a-zombie

Вернуться в «Python»