Python到c++通信失败



我在python中有4个numpy数组。我把它们发送给一个衍生的c++进程。这适用于小数组,但是当数组太大时,c++程序读取(看起来与机器的字节顺序相反(little))一个不正确的值。

python/numpy数组的典型值为0.25、0.5、0.7等。

, c++程序会正确地接收这些元素,直到元素数达到数千个,然后c++程序开始接收奇怪的值,这些值似乎是它应该得到的小端值的大端版本。它与同步无关,因为无论大小如何,中间的数组都会完美地发送所有数据。只有我的第一个和最后一个数组可以这样做——尽管所有python/numpy数组都被强制为相同的类型。

一旦数组太大:c++接收的值像:-4.34345e-266, -5.67456e-50等

有没有人猜测为什么会发生这种情况?我已经被这个问题困扰了一段时间了。

编辑:这似乎是一个平台问题。代码在我的本地计算机(Ubuntu 18.04, python 3.6.9, g++ 7.5.0)上运行,但在Amazon AWS (Ubuntu 18.04, python 3.6.9, g++ 7.5.0)上运行失败——似乎规格相同。我是否应该考虑其他的平台依赖性?编辑2:我已经把范围缩小了。这似乎是一个一旦经过一定时间就会发生的问题,而不是在特定数组大小之后发生的问题。这就是为什么我的本地机器在问题出现之前传输了所有数据。AWS使用vCPU(虚拟),进程之间的通信可能需要更长的时间,这就是为什么我在云服务器上注意到它,而不是我的本地服务器…任何可能导致这种情况的建议都是有帮助的。
# python
...
p = subprocess.Popen(
'shell text to launch C++ process',
shell=True, 
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
...
<loop through all arrays>
array = arrays[i]

p.stdin.write(<the size and type of array>)
<looping through numpy array>
value = array[x][y]
b = struct.pack('<d', value)
p.stdin.write(b)
p.stdin.flush()
// c++
...
<loop through expected arrays>

int size;
r = fread(&size, sizeof(int), 1, stdin);
<allocate array with size and type>
<loop through size of array>
double value;
r = fread(&value, sizeof(double), 1, stdin);

<input values into allocated array>
以下是python在发送之前和c++在接收之后的唯一值(aid是数组的id):
py >> aid:  0  val :  1.5147748861987186e-07
py >> aid:  0  val :  0.00027064327098285035
py >> aid:  0  val :  0.00032440267655912817
py >> aid:  0  val :  0.00039440984799195717
py >> aid:  0  val :  0.00048666128622491974
py >> aid:  0  val :  0.0006088895533821487
py >> aid:  0  val :  0.0007693269194044289
py >> aid:  0  val :  0.0009713703111738414
py >> aid:  0  val :  0.0011995490513889394
py >> aid:  0  val :  0.0013989766453051436
py >> aid:  0  val :  0.0014816246426333445
py >> aid:  0  val :  0.000971370311173842
py >> aid:  0  val :  0.000608889553382149
py >> aid:  0  val :  0.0003944098479919573
py >> aid:  0  val :  0.0003244026765591282
py >> aid:  0  val :  0.0006091367065721885
py >> aid:  0  val :  1.1195904948938864
py >> aid:  0  val :  0.0006535893828657839
py >> aid:  0  val :  0.0006896927523924802
py >> aid:  0  val :  0.0007134077346636406
py >> aid:  0  val :  0.0007216922125962245
py >> aid:  0  val :  0.17
py >> aid:  0  val :  205.0
py >> aid:  0  val :  0.0016111429295754896
py >> aid:  0  val :  0.001897252365911768
py >> aid:  0  val :  0.0020511342434220143
py >> aid:  0  val :  0.0021170160163027038
py >> aid:  0  val :  0.0021201443585756935
py >> aid:  0  val :  2.407359807268656e-06
py >> aid:  0  val :  0.0011768390663802282
py >> aid:  0  val :  0.0013958354194843637
py >> aid:  0  val :  0.001670834944478645
py >> aid:  0  val :  0.002016004763800768
py >> aid:  0  val :  0.002444680031953682
py >> aid:  0  val :  0.0029617508597233667
py >> aid:  0  val :  0.0035475199335043986
py >> aid:  0  val :  0.004133617431826363
py >> aid:  0  val :  0.0045900107907456715
py >> aid:  0  val :  0.0047657186623283965
py >> aid:  0  val :  0.004133617431826364
py >> aid:  0  val :  0.0035475199335044
py >> aid:  0  val :  0.0024446800319536835
py >> aid:  0  val :  0.0016708349444786454
py >> aid:  1  val :  0.0
py >> aid:  1  val :  0.1978674776035768
py >> aid:  2  val :  295.15
c++ >> aid: 0 val: 1.51477e-07
c++ >> aid: 0 val: 0.000270643
c++ >> aid: 0 val: 0.000324403
c++ >> aid: 0 val: 0.00039441
c++ >> aid: 0 val: 0.000486661
c++ >> aid: 0 val: 0.00060889
c++ >> aid: 0 val: 0.000769327
c++ >> aid: 0 val: 0.00097137
c++ >> aid: 0 val: 0.00119955
c++ >> aid: 0 val: 0.00139898
c++ >> aid: 0 val: 0.00148162
c++ >> aid: 0 val: 0.00097137
c++ >> aid: 0 val: 0.00060889
c++ >> aid: 0 val: 0.00039441
c++ >> aid: 0 val: 0.000324403
c++ >> aid: 0 val: 0.000609137
c++ >> aid: 0 val: 1.11959
c++ >> aid: 0 val: 0.000653589
c++ >> aid: 0 val: 0.000689693
c++ >> aid: 0 val: 0.000713408
c++ >> aid: 0 val: 0.000721692
c++ >> aid: 0 val: 0.17
c++ >> aid: 0 val: 205
c++ >> aid: 0 val: -7.26344e+201
c++ >> aid: 0 val: -7.26344e+201
c++ >> aid: 0 val: -1.11628e-125
c++ >> aid: 0 val: -1.11628e-125
c++ >> aid: 0 val: -7.26344e+201
c++ >> aid: 0 val: -4.31009e+12
c++ >> aid: 0 val: -1.49167e-154
c++ >> aid: 0 val: -1.49167e-154
c++ >> aid: 0 val: -4.31009e+12
c++ >> aid: 0 val: -7.26344e+201
c++ >> aid: 0 val: -4.31009e+12
c++ >> aid: 0 val: 3.27272e+181
c++ >> aid: 0 val: -7.26344e+201
c++ >> aid: 0 val: 3.27272e+181
c++ >> aid: 0 val: 3.27272e+181
c++ >> aid: 0 val: 2.31398e-204
c++ >> aid: 0 val: -7.26344e+201
c++ >> aid: 0 val: 2.31398e-204
c++ >> aid: 0 val: 2.31398e-204
c++ >> aid: 0 val: -3.46371e+65
c++ >> aid: 0 val: -7.26344e+201
c++ >> aid: 0 val: -3.46371e+65
c++ >> aid: 0 val: -3.46371e+65
c++ >> aid: 0 val: 3.12744e+114
c++ >> aid: 0 val: -7.26344e+201
c++ >> aid: 0 val: 3.12744e+114
c++ >> aid: 0 val: 3.12744e+114
c++ >> aid: 0 val: 1.23842e+146
c++ >> aid: 0 val: 1.23842e+146
c++ >> aid: 0 val: 5.81017e-69
c++ >> aid: 0 val: 9.07095e+38
c++ >> aid: 0 val: 9.07095e+38
c++ >> aid: 0 val: -3.08372e+147
c++ >> aid: 0 val: -3.08372e+147
c++ >> aid: 0 val: 2.46041e+154
c++ >> aid: 0 val: 2.46041e+154
c++ >> aid: 0 val: -4.86069e-290
c++ >> aid: 0 val: -4.86069e-290
c++ >> aid: 0 val: 1.33577e-275
c++ >> aid: 0 val: 1.33577e-275
c++ >> aid: 0 val: 8.41193e+15
c++ >> aid: 0 val: 8.41193e+15
c++ >> aid: 0 val: 4.09165e-233
c++ >> aid: 0 val: 4.09165e-233
c++ >> aid: 0 val: -7.36835e+223
c++ >> aid: 0 val: -7.36835e+223
c++ >> aid: 0 val: -6.59221e+62
c++ >> aid: 0 val: -6.59221e+62
c++ >> aid: 0 val: -1.60471e-283
c++ >> aid: 0 val: -1.60471e-283
c++ >> aid: 0 val: -6.59221e+62
c++ >> aid: 0 val: -7.36835e+223
c++ >> aid: 0 val: -7.36835e+223
c++ >> aid: 0 val: 4.09165e-233
c++ >> aid: 0 val: 4.09165e-233
c++ >> aid: 0 val: 8.41193e+15
c++ >> aid: 0 val: 1.33577e-275
c++ >> aid: 0 val: 1.33577e-275
c++ >> aid: 0 val: -4.86069e-290
c++ >> aid: 0 val: 2.46041e+154
c++ >> aid: 0 val: 2.46041e+154
c++ >> aid: 0 val: -3.08372e+147
c++ >> aid: 0 val: 9.07095e+38
c++ >> aid: 0 val: 5.81017e-69
c++ >> aid: 1 val: 0
c++ >> aid: 1 val: 0.197867
c++ >> aid: 2 val: 295.15

这里有一个例子。运行python代码,看看它是如何通信的。在创建这个例子时,我注意到dim的限制是144,这意味着我的计算机在失败之前可以传输的最大字节是165888。(编辑:这是由于管道阻塞时,读和写都在同一个线程中,正如在下面的答案中指出的,但我的实际代码使用线程和非阻塞。这个问题似乎仍然与时间流逝有关,因为它在我的本地服务器上工作)

# python 3
import numpy
import subprocess
import struct
import sys
import time
s = subprocess.Popen(
'g++ -Ofast -pthread -o script comm_test.cpp && ./script',
shell=True, 
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=-1,
)
dim = 4
a = numpy.arange(dim*dim, dtype=numpy.float64).reshape((dim, dim))
print(a)
bdim = dim.to_bytes(4, byteorder=sys.byteorder)
s.stdin.write(bdim)
for i in range(dim):
for j in range(dim):
b = struct.pack('<d', a[i][j])
s.stdin.write(b)
s.stdin.flush()
while True:
data = s.stderr.readline()
text = '[c++] {}'.format(data.decode('utf-8'), end='')
print(text)
if 'done' in text:
break
// comm_test.cpp
#include <iostream>
#include <stdio.h>
#include <streambuf>
using namespace std;
int main(){
cerr << "started" << endl;
int r, dim;
r = fread(&dim, sizeof(int), 1, stdin);
cerr << "dim: " << dim << endl;
double* array = new double[dim*dim];
for(int i = 0; i < dim*dim; i++){
double val;
r = fread(&val, sizeof(double), 1, stdin);
array[i] = val;
cerr << val << endl;
}
cerr << "done" << endl;
return 0;
}

你的问题不在Python这一边。您的问题是C应用程序正在填充其标准输出管道缓冲区并阻塞,因为您的Python代码在完成写入之前不会读取任何内容。

要进行这种通信,需要同时进行读和写操作。你可以用一个简单的TCP套接字做到这一点,但你会有同样的问题;缓冲区不是无限大的

我明白了。我在某个地方有一个循环,它在计时器上ping c++进程。它是在所有初始数据传输完成之前运行的,因此,ping会在传输过程中发送几个字节的数据(因此我无法确定准确的错误点),这将丢弃所有后续的数据块。我假设我的本地计算机IPC比AWS云vcpu IPC快,这是对的。这就是为什么我的本地计算机工作-初始数据传输能够超过定时器循环。

既然这对任何人都没有多大帮助,我可以发布一个更好的版本,一个简单的进程间PIPE通信(有线程,所以它是非阻塞的[不限制数据传输]):

# python 3
import numpy
import subprocess
import struct
import sys
import time
import threading
from time import perf_counter
s = subprocess.Popen(
'g++ -Ofast -pthread -o script comm_test.cpp && ./script',
shell=True, 
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
def reader(s):
while True:
data = s.stdout.readline()
text = '[c++] {}'.format(data.decode('utf-8'), end='')
print(text)
if 'done' in text:
break
r = threading.Thread(target=reader, args=(s,))
r.start()
dim = 1000
a = numpy.arange(dim*dim, dtype=numpy.float64).reshape((dim, dim))
print(a)
bdim = struct.pack('<i', dim)
s.stdin.write(bdim)
t1 = perf_counter()
for i in range(dim):
for j in range(dim):
val = a[i][j]
val = numpy.float64(val)
b = struct.pack('<d', val)
s.stdin.write(b)
s.stdin.flush()
t2 = perf_counter()
r.join()
print('finished in {:.4f} seconds'.format(t2-t1))
// c++ comm_test.cpp
#include <iostream>
#include <stdio.h>
#include <streambuf>
using namespace std;
int main(){
cerr << "started" << endl;
int r, dim;
r = fread(&dim, sizeof(int), 1, stdin);
cerr << "dim: " << dim << endl;
double* array = new double[dim*dim];
for(int i = 0; i < dim*dim; i++){
double val;
r = fread(&val, sizeof(double), 1, stdin);
array[i] = val;
cerr << val << endl;
}
cerr << "done" << endl;
return 0;
}

最新更新