关于ZAKER 融媒体解决方案 合作 加入

使用 Python 子进程从 stdout 上的 C 程序捕获输出 .

CocoaChina 10-21

我想从我正在启动的 C 程序中捕获输出:

p = subprocess.Popen ( [ "make", "run_pci" ] , stdout=subprocess.PIPE, cwd="/home/ecorbett/hello_world_pthread" ) for ln in p.stdout:

唯一的问题是我在 C 程序完成之前不会输出 , 实际上我需要在程序运行时逐行输出 . 更复杂的是 , 我必须解析每一行 ( 我只需要来自行的某些数据 ) .

例如 , 这里有一些示例输出 : ( 我需要捕获 "Thread on Tile#" )

blahblah blah Thread blahblah blah tile 1: On blahblah blah Thread blahblah blah tile 2: OFF blahblah blah Thread blahblah blah tile 3 : Disable

我注意到我在下面链接的文章似乎有同样的问题 . 我试图弄清楚如何适应我的情况?

Getting realtime output from ffmpeg to be used in progress bar ( PyQt4, stdout )

Python 新手 , 所以示例代码非常感谢 !!!

你不能像那样使用 p.stdout; 如果您要求 " 整个标准输出 ", 则只有在过程终止 ( 或管道缓冲器填充 , 这可能需要很长时间 ) 时才可用 .

您需要逐行读取进程的 stdout.

while True: ln = p.stdout.readline ( ) if '' == ln: break m = re.search ( "Thread ( ?P<id>d+ ) ", ln ) ; if m: # use m.group ( ) to extract information # e.g. m.group ( 'id' ) will hold the 12345 from "Thread 12345"

最好将 stdout 设置为行缓冲 ( 通常尽可能完全缓冲 ) , 但我认为这只能在被调用程序中完成 .

我们在这里要考虑两个缓冲区 . 一个是 C 程序的输出缓冲区 . 这可能是不存在的 ( 无缓冲输出 ) , 线路缓冲或完全缓冲 ( 1K,4K 或 8K 是一些可能的大小 ) .

在程序中 , 调用 "printf ( ) ". 输出结果如下:

> out, 如果没有缓冲

> 进入缓冲区 ; 如果行缓冲 , 则输出缓冲区中所有换行终止的行 ;

> 进入缓冲区 ; 然后输出第一个 4K, 如果用 4K 缓冲器完全缓冲并且缓冲区比 4K 更饱满 .

现在输出进入 Python 的管道 . 这也可以是完全缓冲 ( stdout ) 或行缓冲 ( readline ) . 所以输出结果如下:

> 对 python 程序的逻辑 , 如果管道中有一个完整的换行终止行 , 我们正在使用 readline

> 到缓冲区 , 如果管道中的数量少于 4K, 我们在 stdout 中使用 "for ln".

在最后一种情况下 , 缓冲区将以 4K 块的形式进入 Python 逻辑 .

现在让我们想象一个行缓冲的 C 程序向 Python 程序输出一行 , 每行 1K 个字符 ( 如果 C 程序完全缓冲 , 那么可以做的就不多了! )

在循环中读取 stdout, 我们会看到 ( 在 for 循环中 ) :

> t = 0 ……没什么

> t = 1 …没有 ( 缓冲区已满 50% )

> t = 2 …没有 ( 缓冲区已满 75% )

> t = 3 …四行输出

> t = 4 ……没什么

通过 readline 阅读我们会得到:

> t = 0 ……一行

> t = 1 …一行

> t = 2 ……一行

> t = 3 ……一行

在这里 , 我运行 "ping -c 3 -i 2 127.0.0.1", 以便以两秒的间隔将三个数据包发送到 localhost. 一次 ping 操作大约需要 6 秒钟 . 我从 ping 读取输出 , 并打印时间戳 . ping 的整个输出足够小 , 以至于它适合 Python 的全缓冲区 .

#!/usr/bin/pythonimport subprocessfrom time import gmtime, strftimep = subprocess.Popen ( [ "ping", "-c", "3", "-i", "2", "127.0.0.1" ] , stdout=subprocess.PIPE ) for ln in p.stdout: print strftime ( "%H:%M:%S", gmtime ( ) ) + " received " + ln# Now I start the same process again, reading the input the other way.p = subprocess.Popen ( [ "ping", "-c", "3", "-i", "2", "127.0.0.1" ] , stdout=subprocess.PIPE ) while True: ln = p.stdout.readline ( ) if '' == ln: break print strftime ( "%H:%M:%S", gmtime ( ) ) + " received " + ln

我在 Linux 机器上收到的输出正如预期的那样:

( nothing for the first six seconds ) 15:40:10 received PING 127.0.0.1 ( 127.0.0.1 ) 56 ( 84 ) bytes of data.15:40:10 received 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.037 ms15:40:10 received 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.034 ms15:40:10 received 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.031 ms15:40:10 received15:40:10 received --- 127.0.0.1 ping statistics ---15:40:10 received 3 packets transmitted, 3 received, 0% packet loss, time 3998ms15:40:10 received rtt min/avg/max/mdev = 0.031/0.034/0.037/0.002 ms15:40:10 received PING 127.0.0.1 ( 127.0.0.1 ) 56 ( 84 ) bytes of data.15:40:10 received 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.041 ms15:40:12 received 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.039 ms15:40:14 received 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.035 ms15:40:14 received15:40:14 received --- 127.0.0.1 ping statistics ---15:40:14 received 3 packets transmitted, 3 received, 0% packet loss, time 3999ms15:40:14 received rtt min/avg/max/mdev = 0.035/0.038/0.041/0.005 ms

以上内容由"CocoaChina"上传发布 查看原文
相关标签 python进程程序