我在python中有4个numpy数组。我将它们发送到一个派生的c++进程中。这适用于小数组,但是当数组变得太大时,c++程序会读取一个不正确的值(看起来与机器(小)相反的字节顺序)。
python/numpy数组的典型值是0.25、0.5、0.7等。
c++程序将正确地接收这些值,直到得到数千个元素,然后c++程序开始接收奇怪的值,这些值似乎是它应该得到的小endian值的大端版本。它与同步无关,因为中间数组完美地发送所有数据,不管大小如何。这只是我的第一个也是最后一个数组,尽管所有python/numpy数组都被迫是相同的类型。
一旦数组变得太大: c++接收的值如下:-4.34345e-266,-5.67456e-50,等等。
有谁能猜到为什么会发生这种事?我被困在这上面已经有一段时间了。
编辑:这似乎是一个平台问题。这些代码在我的本地计算机(Ubuntu18.04,python3.6.9,g++ 7.5.0)上工作,但在Amazon (Ubuntu18.04,python3.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;
}发布于 2021-10-28 23:02:45
您的问题不是Python方面的。您的问题是C应用程序正在填充它的stdout管道缓冲区和阻塞,因为您的Python代码在完成编写之前不会读取任何内容。
要进行这种交流,需要读写同时进行。您可以使用一个简单的TCP套接字来完成这个任务,但是您也会遇到同样的问题;缓冲区不是无限大的。
发布于 2021-10-29 15:12:41
我想通了。我在某个地方有一个循环,它在定时器上敲击c++进程。它是在所有初始数据传输完成之前运行的,因此ping会在传输过程中的某个位置发送几字节数据(因此我无法确定一个确切的错误点),这将抛出所有后续的数据片段。我正确地假设我的本地计算机IPC比更快。这就是为什么我的本地计算机工作-最初的数据传输能够超过速度的定时器循环.
由于这不会对任何人有多大帮助,所以我可以发布一个更好版本的简单进程间管道通信(使用线程,因此它对传输的数据没有任何限制):
# 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;
}https://stackoverflow.com/questions/69758580
复制相似问题