我试图通过使用子进程Python模块将一些重复计算外包到C ++程序来加速Python程序。
为了说明我的问题,我采用了一个简单的C ++代码,它返回了输入的两倍。一百万个整数需要16秒,这似乎很慢。
这是C ++程序(double.exe):
#include <iostream>
using namespace std;
int main()
{
int a;
bool goon = true;
while (goon)
{
cin >> a;
cout << 2 * a << endl;
if (a == 0)
goon= false;
}
}
这里是Python 3代码:
from time import time
from subprocess import PIPE,Popen
cmd = ["double"]
process = Popen(cmd, stdin=PIPE,stdout=PIPE, bufsize=32,universal_newlines=True, shell=True)
t0 = time()
for i in range(1,int(1e6)):
print(i, file=process.stdin, flush=True)
output = int(process.stdout.readline())
dt = time() - t0
print("Time to communicate : %fs" % dt)
print(0,file=process.stdin,flush=True) # close 'double' program
沟通时间:16.029137s
对我而言,它如此之慢的原因只能是通过管道进行Python进程和C ++程序之间的通信,但我还没有找到如何加速它。使用子进程或其他库加速此通信的任何解决方案?
我在Windows上使用Python 3.5.2。
答案 0 :(得分:3)
问题不是stdin通信本身,而是大规模的上下文切换。你做了一个非常小的任务&#34;在C ++代码中,但对于每个这样的&#34;任务&#34; python代码应该将数据写入管道,刷新,睡眠,C ++部分唤醒,解析输入,计算结果,打印输出,刷新并进入睡眠状态。然后python代码唤醒,等等。
进入睡眠和醒来(以及相关的上下文切换)并不是免费的。随着&#34;任务的大小&#34; (将输入乘以2)这种开销大部分时间消耗。
你可以修复&#34;通过批量提供工作到C ++程序,或者有更大的任务。或两者兼而有之。
例如,如果在每次写入后刷新管道,那么使用数百万个数字的相同作业,但使用10个数字的批次在我的盒子上运行速度快2倍。代码:
for i in range(1,int(1e5)):
for j in range(1, 10):
print(i*10 + j, file=process.stdin, flush=True)
for j in range(1, 10):
output = int(process.stdout.readline())
如果每10个号码只进行一次刷新,它的运行速度比前一个例子慢1.5倍(或者比原始代码快3倍):
for i in range(1,int(1e5)):
for j in range(1, 10):
print(i*10 + j, file=process.stdin)
process.stdin.flush()
for j in range(1, 10):
output = int(process.stdout.readline())
如果&#34;任务&#34;然后,您必须为上下文切换支付的价格相同。但与任务规模相比,它并没有那么大。例如,让我们想象上下文切换需要0.1秒(在现实生活中它的方式更小,这只是一个例子)。如果任务是乘法,例如1ms(再次,仅举例),那么与任务相比,上下文切换开销是10000%。但如果您的任务很繁重并且需要执行1秒,则开销仅为10%。相对值的1000倍差异。
答案 1 :(得分:1)
只是一个猜测,但可能是因为std::endl不仅写了一个新的行字符而且还刷新了输出流。冲洗之夜是花费最多时间的部分。因此,如果你只是写
,它可能会更快std::cout << 2 * a << "\r\n"; //Windows style line break
或
{{1}}
(注意:未经测试是否有效或实际上需要隐式刷新。)