往返于 2 Python 个子流程的循环管道
Circle Piping to and from 2 Python Subprocesses
我需要有关子流程模块的帮助。这个问题听起来可能会重复,而且我已经看到许多以多种方式与它相关的文章。但即使这样我也无法解决我的问题。它是这样的:
我有一个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()
问题出在这里
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 个进程。
此外,初始化阶段与 运行ning 阶段没有区别,除了您提供输入数据。
您可以做些什么来简化并使其发挥作用:
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 个进程 运行ning,证明您可以做到这一点,只需按如下方式修复循环(通过在循环中移动 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
如果您希望第一个命令 a
的输出作为第二个命令 b
的输入,那么 b
的输出又是 a
的输入——像一条蛇吃它的尾巴一样绕圈——然后你不能在循环中使用 .communicate()
:.communicate()
不会 return 直到进程结束并且所有输出被消耗。
一种解决方案是使用命名管道(如果 open()
在您的系统上不会在这种情况下阻塞):
#!/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
它模拟来自 @alexander barakin answer 的 a < fifo | b > fifo
shell 命令。
这里是更复杂 的解决方案,它通过 python parent 过程收集数据:
#!/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
此代码通过 OS 管道使用重定向将 a
的输出连接到 b
的输入(就像 a | b
shell 命令所做的那样)。
为了完成循环,b
的输出被复制到 a
在 parent Python 代码中使用 shutil.copyfileobj()
的输入。
此代码可能有 buffering issues:进程之间有多个缓冲区:C stdio 缓冲区,Python 文件中的缓冲区 objects 包装管道(由 [=28 控制) =]).
bufsize=0
关闭 Python 端的缓冲,数据可用时立即复制。当心,bufsize=0
可能会导致部分写入——您可能需要内联 copyfileobj()
并再次调用 write() 直到写入所有读取数据。
调用 setvbuf(stdout, (char *) NULL, _IOLBF, 0)
,在您的 C 程序中生成标准输出 line-buffered:
#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;
}
输出
10
9
8
7
6
5
4
3
2
1
0
-1
输出相同。
由于 C child 程序的编写和执行方式,您可能还需要在 a.stdin.write()
and/or 末尾捕获并忽略 BrokenPipeError
异常a.stdin.close()
(a
进程可能已经停止,而 b
有未复制的数据)。
我需要有关子流程模块的帮助。这个问题听起来可能会重复,而且我已经看到许多以多种方式与它相关的文章。但即使这样我也无法解决我的问题。它是这样的:
我有一个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()
问题出在这里
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 个进程。
此外,初始化阶段与 运行ning 阶段没有区别,除了您提供输入数据。
您可以做些什么来简化并使其发挥作用:
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 个进程 运行ning,证明您可以做到这一点,只需按如下方式修复循环(通过在循环中移动 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
如果您希望第一个命令 a
的输出作为第二个命令 b
的输入,那么 b
的输出又是 a
的输入——像一条蛇吃它的尾巴一样绕圈——然后你不能在循环中使用 .communicate()
:.communicate()
不会 return 直到进程结束并且所有输出被消耗。
一种解决方案是使用命名管道(如果 open()
在您的系统上不会在这种情况下阻塞):
#!/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
它模拟来自 @alexander barakin answer 的 a < fifo | b > fifo
shell 命令。
这里是更复杂 的解决方案,它通过 python parent 过程收集数据:
#!/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
此代码通过 OS 管道使用重定向将 a
的输出连接到 b
的输入(就像 a | b
shell 命令所做的那样)。
为了完成循环,b
的输出被复制到 a
在 parent Python 代码中使用 shutil.copyfileobj()
的输入。
此代码可能有 buffering issues:进程之间有多个缓冲区:C stdio 缓冲区,Python 文件中的缓冲区 objects 包装管道(由 [=28 控制) =]).
bufsize=0
关闭 Python 端的缓冲,数据可用时立即复制。当心,bufsize=0
可能会导致部分写入——您可能需要内联 copyfileobj()
并再次调用 write() 直到写入所有读取数据。
调用 setvbuf(stdout, (char *) NULL, _IOLBF, 0)
,在您的 C 程序中生成标准输出 line-buffered:
#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;
}
输出
10
9
8
7
6
5
4
3
2
1
0
-1
输出相同。
由于 C child 程序的编写和执行方式,您可能还需要在 a.stdin.write()
and/or 末尾捕获并忽略 BrokenPipeError
异常a.stdin.close()
(a
进程可能已经停止,而 b
有未复制的数据)。