我需要有关子进程模块的帮助。这个问题可能听起来很重复,我在很多方面看过很多与之相关的文章。但即便如此,我也无法解决我的问题。具体如下:
我有一个C程序2.c它的内容如下:
#include<stdio.h>
int main()
{
int a;
scanf("%d",&a);
while(1)
{
if(a==0) //Specific case for the first input
{
printf("%d\n",(a+1));
break;
}
scanf("%d",&a);
printf("%d\n",a);
}
return 0;
}
我需要编写一个python脚本,首先使用subprocess.call()编译代码,然后使用Popen打开两个进程来执行相应的C程序。现在,第一个过程的输出必须是第二个过程的输入,反之亦然。基本上,如果我的初始输入为0,则第一个过程输出2,由第二个过程输出。它反过来输出3等等。
以下脚本是我的想法,但它有缺陷。如果有人可以帮助我,我会非常感激。
from subprocess import *
call(["gcc","2.c"])
a = Popen(["./a.out"],stdin=PIPE,stdout=PIPE) #Initiating Process
a.stdin.write('0')
temp = a.communicate()[0]
print temp
b = Popen(["./a.out"],stdin=PIPE,stdout=PIPE) #The 2 processes in question
c = Popen(["./a.out"],stdin=PIPE,stdout=PIPE)
while True:
b.stdin.write(str(temp))
temp = b.communicate()[0]
print temp
c.stdin.write(str(temp))
temp = c.communicate()[0]
print temp
a.wait()
b.wait()
c.wait()
答案 0 :(得分:1)
问题在这里
while True:
b.stdin.write(str(temp))
temp = b.communicate()[0]
print temp
c.stdin.write(str(temp))
temp = c.communicate()[0]
print temp
一旦communicate
返回,它会注意到更多。您必须再次运行该过程。另外,您不需要同时打开2个进程。
此外,初始阶段与运行阶段没有区别,除了您提供输入数据。
您可以采取哪些措施来简化并使其发挥作用:
from subprocess import *
call(["gcc","2.c"])
temp = str(0)
while True:
b = Popen(["./a.out"],stdin=PIPE,stdout=PIPE) #The 2 processes in question
b.stdin.write(temp)
temp = b.communicate()[0]
print temp
b.wait()
另外,要看到并行运行的2个进程,证明你可以这样做,只需修改你的循环如下(通过在循环中移动Popen
调用):
while True:
b = Popen(["./a.out"],stdin=PIPE,stdout=PIPE) #The 2 processes in question
c = Popen(["./a.out"],stdin=PIPE,stdout=PIPE)
b.stdin.write(str(temp))
temp = b.communicate()[0]
print temp
c.stdin.write(str(temp))
temp = c.communicate()[0]
print temp
更好。 b输出馈送c输入:
while True:
b = Popen(["./a.out"],stdin=PIPE,stdout=PIPE) #The 2 processes in question
c = Popen(["./a.out"],stdin=b.stdout,stdout=PIPE)
b.stdin.write(str(temp))
temp = c.communicate()[0]
print temp
答案 1 :(得分:1)
如果您希望第一个命令a
的输出作为第二个命令b
的输入而转而b
的输出为{{1}输入一个像蛇一样吃掉它的尾巴 - 然后你就不能在循环中使用a
:.communicate()
不会返回,直到过程是死了,所有的输出都被消耗了。
一种解决方案是使用命名管道(如果.communicate()
在这种情况下在您的系统上没有阻止):
open()
它模仿来自@alexander barakin answer的#!/usr/bin/env python3
import os
from subprocess import Popen, PIPE
path = 'fifo'
os.mkfifo(path) # create named pipe
try:
with open(path, 'r+b', 0) as pipe, \
Popen(['./a.out'], stdin=PIPE, stdout=pipe) as b, \
Popen(['./a.out'], stdout=b.stdin, stdin=pipe) as a:
pipe.write(b'10\n') # kick-start it
finally:
os.remove(path) # clean up
shell命令。
这是更复杂的解决方案,它通过python父进程汇集数据:
a < fifo | b > fifo
此代码使用通过OS管道的重定向将#!/usr/bin/env python3
import shutil
from subprocess import Popen, PIPE
with Popen(['./a.out'], stdin=PIPE, stdout=PIPE, bufsize=0) as b, \
Popen(['./a.out'], stdout=b.stdin, stdin=PIPE, bufsize=0) as a:
a.stdin.write(b'10\n') # kick-start it
shutil.copyfileobj(b.stdout, a.stdin) # copy b's stdout to a' stdin
的输出连接到a
的输入(如b
shell命令所做的那样)。
要完成圈子,a | b
的输出将使用b
复制到父Python代码中的a
输入。
此代码可能有buffering issues:进程之间有多个缓冲区:C stdio缓冲区,包装管道的Python文件对象中的缓冲区(由shutil.copyfileobj()
控制)。
bufsize
关闭Python端的缓冲,数据一旦可用就会被复制。请注意,bufsize=0
可能导致部分写入 - 您可能需要内联bufsize=0
并再次调用write()直到写入所有读取数据。
调用copyfileobj()
,使stdout行缓冲在C程序中:
setvbuf(stdout, (char *) NULL, _IOLBF, 0)
#include <stdio.h>
int main(void)
{
int a;
setvbuf(stdout, (char *) NULL, _IOLBF, 0); /* make line buffered stdout */
do {
scanf("%d",&a);
printf("%d\n",a-1);
fprintf(stderr, "%d\n",a); /* for debugging */
} while(a > 0);
return 0;
}
输出相同。
由于编写和执行C子程序的方式,您可能还需要在10
9
8
7
6
5
4
3
2
1
0
-1
和/或BrokenPipeError
({{}的末尾捕获并忽略a.stdin.write()
异常。当a.stdin.close()
)中存在未复制的数据时,1}}进程可能已经死亡。