2015-08-06 1 views
3

Я бег два процесса одновременно в питоне с помощью модуля подпроцесса:Почему Popen.stdout содержит только часть вывода?

p_topic = subprocess.Popen(['rostopic','echo','/msg/address'], stdout=PIPE) 
p_play = subprocess.Popen(['rosbag','play',bagfile_path]) 

Это ROS процессов: p_topic прослушивает .bag файла для воспроизведения и выводят некоторую информацию из этого .bag файла в поток стандартного вывода; Затем я хочу получить доступ к этому выводу, используя объект p_topic.stdout (который ведет себя как файл).

Однако, что я нахожу, это то, что объект p_topic.stdout содержит только первые ~ 1/3 выходных строк, которые он должен иметь, то есть по сравнению с двумя командами вручную, одновременно в двух оболочках бок о бок ,

Я пробовал ждать много секунд для вывода, но это ничего не меняет, его примерно такое же соотношение линий, отснятых p_topic.stdout каждый раз. Любые намеки на то, что это может быть, будут очень признательны!

EDIT:

Вот код чтения:

#wait for playing to stop 
while p_play.poll() == None: 
    time.sleep(.1) 

time.sleep(X)#wait for some time for the p_topic to finish 
p_topic.terminate() 

output=[] 
for line in p_topic.stdout: 
    output.append(line) 

Обратите внимание, что значение X в time.sleep (X) не имеет никакого значения

+2

завершает ли ваш процесс? Вы [wait] (https://docs.python.org/2/library/subprocess.html#subprocess.Popen.wait) за него перед выполнением последнего 'read'? Вы должны показать код чтения – goncalopp

+2

Кроме того, вы можете использовать ['check_output'] (https://docs.python.org/2/library/subprocess.html#subprocess.check_output), это упрощает работу – goncalopp

+0

Are вы уверены, что не дожидаетесь ввода? Он не ждет каких-либо входных данных при запуске с терминала? –

ответ

0

стоит процесс пытается общаться /Подождите? а не спать, и это решит вашу проблему?

У меня это для общего назначения, поэтому не уверен, можете ли вы принять это и изменить его на то, что вам нужно?

executable_Params = "{0} {1} {2} {3} {4}".format(my_Binary, 
                 arg1, 
                 arg2, 
                 arg3, 
                 arg4) 

    # execute the process 
    process = subprocess.Popen(shlex.split(executable_Params), 
           shell=False, 
           stderr=subprocess.PIPE, 
           stdout=subprocess.PIPE) 


    stdout, stderr = process.communicate() 
    ret_code = process.wait() 

    if ret_code == 0: 
     return 0 
    else: 
     #get the correct message from my enum method 
     error_msg = Process_Error_Codes(ret_code).name 
     raise subprocess.CalledProcessError(returncode=ret_code, 
              cmd=executable_Params) 
+0

Спасибо, но я думаю .communicate() ждет завершения процесса? ростопический процесс должен быть завершен вручную (он остается активным до ctrl-c в терминале). – LPA

+0

btw это работало для чтения stdout/stderr: process = subprocess.Popen (my_Params, shell = True, stderr = subprocess.PIPE, stdout = subprocess.PIPE) в то время как True: ERR = process.stderr.read (255) печать stdo если из == '' и process.poll() = None: перерыв если из =! '': proc_err_flag = 1 sys.stdout.write (out) sys.stdout.flush() – Psymon25

1

По умолчанию, когда процесс stdout-х не подключен к терминалу, выход блока в буфер. При подключении к терминалу он буферизируется по строке. Вы ожидаете получить полные строки, но вы не можете, если rostopic не буферизует или явно строит буферы своего stdout (если это программа на C, вы можете использовать setvbuf, чтобы сделать это автоматически).

Другая возможность (возможно, перекрытие) состоит в том, только то, что удалось уложить в трубу, которая должна быть слита, когда вы читаете процесс stdout. В этом случае вам нужно будет либо создать поток, чтобы удалить трубопровод из Python, либо использовать основной компонент потока select для мониторинга и слива трубы (в сочетании с опросом другого процесса). Поток, как правило, проще, хотя вам нужно быть осторожным, чтобы избежать проблем с безопасностью потоков.

+0

Привет, только для подтверждения выяснилось, что ваша вторая возможность случалась. Я нашел этот блог об этом: http://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/ Я обойду его, просто написав локальный файл - хотя кажется, что есть более разумные способы справиться с этим, если вывод был действительно большим, как вы упомянули, или с определением локальных FIFO-каналов. – LPA

+0

Этот блог неправильный; используя связь(), фактически избегает проблемы, о которой он говорит (хотя, возможно, у какой-то старой версии Python была ошибка), потому что Python неявно использует select и/или threads, чтобы избежать тупика. Проблема в том, что в вашем случае вы хотите получить частичный выход (так что общение не является вариантом). – ShadowRanger