Python和C 程序与子过程之间的沟通非常缓慢

Very slow communication between Python and C++ program with subprocess

本文关键字:非常 缓慢 之间 过程 程序 Python      更新时间:2023-10-16

我试图通过使用子过程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。

问题本身不是stdin通信,而是大规模上下文切换。您在C 代码中执行一个很小的"任务",但是对于每个此类任务,Python代码都应将数据写入管道,冲洗,睡觉,C 零件醒来,醒来,解析输入,计算结果,打印结果,打印出来。输出,冲洗并入睡。然后,Python代码醒来等等

睡觉并醒来(以及关联的上下文切换)不是免费的。随着"任务"的大小(将输入乘以两个),这大多数时候都会消耗。

您可以通过分批向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())

如果"任务"更大,那么您必须为上下文开关支付的价格相同。但是,与任务的大小相比,这并不大。例如,让我们想象上下文开关需要0.1秒(在现实生活中它越小,这只是一个例子)。如果任务是在1毫秒中完成的乘法(例如,仅仅是),则与任务相比,上下文开关开销为10000%。但是,如果您的任务很重,并且需要1次执行,则开销仅为10%。相对值的1000倍。

只是一个猜测,但这可能是由于std :: endl不仅编写了新的行字符,而且还散发出输出流。冲洗式Miight是最花时间的部分。因此,如果您只写

,它可能会更快
std::cout << 2 * a << "n"; //Unix style line break

std::cout << 2 * a << "rn"; //Windows style line break

(注意:未经测试是否有效还是隐式齐平。)