【问题标题】:Why does Popen.stdout contain only part of output?为什么 Popen.stdout 只包含部分输出?
【发布时间】:2015-08-06 10:13:16
【问题描述】:

我在 python 中使用 subprocess 模块同时运行两个进程:

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 的输出行——也就是说,与手动运行这两个命令相比,同时在两个shell 中并排一边。

我尝试等待几秒钟以完成输出,但这并没有改变任何东西,它与p_topic.stdout 每次捕获的行数大致相同。任何有关这可能是什么的提示将不胜感激!

编辑:

阅读代码如下:

#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)

请注意 time.sleep(X) 中的值 X 没有任何区别

【问题讨论】:

  • 您的进程是否终止?在做最后一个read 之前,你是waiting 吗?您应该显示阅读代码
  • 另外,你可能想使用check_output,它会让事情变得更容易
  • 你确定它不等待任何输入吗?从终端运行时它不等待任何输入?
  • 你让自己过得很辛苦,你用的是什么版本的python?
  • 你确定你的输出是纯标准输出吗?也许有些东西会进入标准错误?

标签: python subprocess stdout popen ros


【解决方案1】:

默认情况下,当进程的stdout 未连接到终端时,输出是块缓冲的。当连接到终端时,它是线路缓冲的。您希望得到完整的行,但除非rostopic unbuffers 或显式行缓冲其stdout,否则您不能(如果它是C 程序,您可以使用setvbuf 使其自动化)。

另一种(可能重叠)的可能性是管道缓冲区本身正在填充(管道缓冲区通常相当小),并且因为您从不耗尽它,rostopic 填充了管道缓冲区,然后无限期地阻塞,直到你杀死它,当您阅读过程的stdout 时,只留下设法适合管道的东西被排出。在这种情况下,您需要生成一个线程以保持管道从 Python 中排出,或者让您的主线程使用 select 模块组件来监视和排出管道(与轮询其他进程混合)。线程通常更容易,但您确实需要小心避免线程安全问题。

【讨论】:

  • 您好,为了确认一下,原来您的第二种可能性正在发生。我找到了关于它的博客:thraxil.org/users/anders/posts/2008/03/13/… 我只是通过写入本地文件来解决它 - 尽管如果输出真的像你提到的那样大,或者定义本地文件,看起来好像有更聪明的方法来处理它先进先出管道
  • 那个博客是错误的;使用communicate() 实际上避免了他所说的问题(尽管某些旧版本的Python 可能存在错误),因为Python 隐式使用选择和/或线程来避免那里的死锁。问题是,在你的情况下,你想获得部分输出(所以沟通不是一种选择)。
【解决方案2】:

是否值得尝试进程通信/等待?而不是睡觉,这会解决你的问题吗?

我有这个是通用的,所以不确定你是否可以把它改成你需要的?

    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)

【讨论】:

  • 谢谢,但我认为 .communicate() 等待进程终止? rostopic 进程需要手动终止(它保持活动状态,直到终端中的 ctrl-c)
  • 顺便说一句,这适用于读取 stdout/stderr:process = subprocess.Popen(my_Params, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) while True: err = process.stderr。 read(255) print stdo if out == '' and process.poll() != None: break if out != '': proc_err_flag = 1 sys.stdout.write(out) sys.stdout.flush()跨度>
猜你喜欢
  • 2012-09-24
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2019-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-17
相关资源
最近更新 更多