【发布时间】:2021-12-13 22:06:06
【问题描述】:
我在 python 中有 4 个 numpy 数组。我将它们发送到一个衍生的 c++ 进程。这适用于小数组,但是当数组变得太大时,c++ 程序会读取(看起来与机器的相反字节顺序(小))一个不正确的值。
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 中的 unique 值,以及在接收后在 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;
}
【问题讨论】:
-
“太大”到底是什么意思?你对它开始破坏的数组大小有一个估计吗?
-
@LayneBernardo 大约 30,000 个或更多元素
-
这只是一种预感,我对 Python 没有太多经验,但我有点怀疑您可能遇到了 stdin 缓冲区的某种问题。作为故障排除步骤,您可以尝试禁用标准输入缓冲区,如下所述:stackoverflow.com/questions/3670323/…
-
@LayneBernardo 感谢您的输入,我尝试了非缓冲,但没有成功。
-
您的代码过于粗略和不完整,无法确定任何事情。请给出一个合适的“Minimal Complete Reproducible Example”。您是否尝试过计算发送和接收的值的数量?
标签: python c++ amazon-web-services endianness fread