Как найти время выполнения нескольких подпроцессов?

У меня есть список команд Linux, и я запускаю каждую команду, используя модуль подпроцесса, мне нужно выяснить, как я могу найти время выполнения каждой из команд и вернуть время выполнения в списке или dict, в случае dict Ключ может быть именем команды, а значение - временем в секундах.

т.е. момент (Popen object).poll() == 0 отделки должны определить время окончания.

Я использую Python 3.5.2

Например:

import time
import shlex
from subprocess import *`

#list of commands
commands = ['sleep 5', 'ls -l', 'find /usr','sleep 3','uptime']

#executing each command in the list
for command in commands:
     cmd = shlex.split(command)
     # Need to time this and the moment it is finished executing.
     x = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)

Должен вернуться / распечатать:

- Commands   Time(secs)
- sleep 5     5.0004   #whatever the time it takes
- ls -l       0.000    #and so on....

2 ответа

Решение

Popen это техника "беги на заднем плане" бедняка. У вас есть контроль над процессом, но если вы хотите подождать, пока он закончится без опроса, вы не сможете.

если вас не волнует вывод, просто время выполнения, вы можете обернуть каждый subprocess.call (Popen больше не нужно) в потоке, и обновить словарь команды => затраченное время

Запуск потока не блокирует, но call блоки, что позволяет вам время выполнения проще.

import threading,time,subprocess,shlex

time_dict = {}

def time_me(command):
    start_time = time.time()
    cmd = shlex.split(command)
    subprocess.call(cmd)
    time_dict[command] = time.time() - start_time

threads = []
commands = ['sleep 5', 'ls -l', 'find /usr','sleep 3','uptime']

for command in commands:
    t = threading.Thread(target=time_me,args=(command,))
    t.start()
    threads.append(t)

for t in threads:
    t.join()

print(time_dict)

Хотя потоки, безусловно, являются решением этой проблемы (при условии правильной обработки общих данных), вы можете альтернативно запустить цикл while:

import time
import shlex
from subprocess import *

#list of commands
commands = ['sleep 5', 'ls -l', 'sleep 3', 'uptime', 'find /usr']
times = {}
running = {}
#executing each command in the list
for command in commands:
    start_time = time.time()
    cmd = shlex.split(command)
    times[command] = time.time()
    running[command] = Popen(cmd,
                             # no shell=True, shlex already did the split
                             stdout=PIPE, stderr=PIPE)

while len(running):
    finished = set()
    for cmd, proc in running.items():
        if proc.poll() is not None:
            times[cmd] = time.time() - times[cmd]
            finished.add(cmd)
        else:
            proc.communicate() # drain the pipe

    for cmd in finished:
        del running[cmd]

print(times)

Обратите внимание, что это не будет блокировать (в отличие от его многопоточной альтернативы), поэтому он может в итоге съесть ваш процессор Чтобы уменьшить нагрузку, вы можете добавить вызов time.sleep в конце цикла, делая результаты немного неточными.

Изменить: Так как вы использовали каналы в примере, я предполагаю, что вы хотите использовать вывод (некоторые из) команд для некоторой значимой обработки. Хотите ли вы или нет, если вы не делаете proc.communicate, вы закончите заполнять свою трубу, блокируя процесс. Кроме того, вы можете, конечно, перенаправить вывод (в какой-нибудь файл или /dev/null). Связь с процессом может также изменить результаты, как и обработка:)

Другие вопросы по тегам