我有这段代码
导入所有需要的库
class VERTEX(Structure):
_fields_ = [("index", c_int),
("x", c_float),
("y", c_float)]
其他东西
这是从顶点列表
创建和数组def writelist_buf(size, nomeID):
Nvert_VERTEX_Array_Type = VERTEX * len(bpy.data.objects[nomeID].data.vertices)
passarr = Nvert_VERTEX_Array_Type()
for i in range(len(passarr)):
vert = bpy.data.objects[nomeID].data.vertices[i]
passarr[i] = VERTEX(vert.index, vert.co[0], vert.co[1])
return passarr
bpy.data.objects [nomeID] .data.vertices是一个顶点列表。
其他东西
这是在def中,并与前一个数组的C程序进行通信
input = writelist_buf(size, nomeID)
c_program_and_args = "here is the program with his arguments(it works)"
cproc = Popen(c_program_and_args, stdin=PIPE, stdout=PIPE)
out, err = cproc.communicate(input)
#the program returns 2 integers separed by a space
return [int(i) for i in out.decode.split()]
size和nomeID在写入列表之前声明。
经过一些“调试”后,我发现writelist_buf传递的类型是“合法的”(它是字节,因为是用c_types创建的数组),但我一直收到Errno32 Broken Pipe或Errno22 Invalid argument .. C程序只是在stdiin中读取所有顶点(如下面的C代码)...
奇怪的想法是,在我正在处理的代码中“集成”之前,我尝试了一个更简单的代码:这个,它有效!
from subprocess import Popen, PIPE
from ctypes import *
class VERTEX(Structure):
_fields_ = [("index", c_int),
("x", c_float),
("y", c_float)]
nverts = 5
vlist = [VERTEX(0,1,1), VERTEX(1,2,2), VERTEX(2,3,3), VERTEX(3,4,4), VERTEX(4,5,5)]
array = VERTEX * nverts
input = array()
for i in range(nverts):
input[i] = vlist[i]
print(type(input))
cproc = Popen("pipeinout.exe random arg", stdin=PIPE, stdout=PIPE)
out, err = cproc.communicate(input)
print(out.decode())
和C代码
#include<stdio.h>
#include<stdlib.h>
typedef struct {
int index;
float x;
float y;
} vertex;
int main(int argc, char* argv[]) {
int n=5;
int i;
printf("%s",argv[1]);
vertex* VV;
VV=(vertex*)malloc(sizeof(vertex)*n);
fread(VV,sizeof(vertex),n,stdin);
//fread(&VV,sizeof(VV),1,stdin);//metti nel valore di VV(non a quello che punta) l'indirizzo passato||sizeof(VV) is the size of a pointer
for(i=0;i<n;i++)
printf(" %i , %f , %f\n",VV[i].index,VV[i].x,VV[i].y);
}
答案 0 :(得分:2)
根据您的评论,我了解您将数百万件物品传递给C程序数百次。在您的情况下,下面的方法(使用子进程的管道输入)可能太慢。可能的替代方案可能是编写C扩展(例如,使用Cython)或使用ctypes
直接调用C函数。您可以单独询问一个单独的问题,详细说明您的用例可能更适合的方法。
如果你选择了一种方法,那么在任何优化之前确保它正常工作(编写一些测试,测量性能,并且只有在需要时才进行优化) - Make it work, make it right, make it fast。
另一方面,没有必要在以后被抛弃的方法上投入太多时间 - 快速失败。
如果C程序的输出有界;代码中的.communicate()
方法有效(source):
import struct, sys
from subprocess import Popen, PIPE
vertex_struct = struct.Struct('i f f')
def pack(vertices, n):
yield struct.pack('i', n)
for v in vertices:
yield vertex_struct.pack(*v)
def main():
try: n = int(sys.argv[1])
except IndexError:
n = 100
vertices = ((i,i+1,i+2) for i in range(n))
p = Popen(["./echo_vertices", "random", "arg"], stdin=PIPE, stdout=PIPE)
out, _ = p.communicate(b''.join(pack(vertices, n)))
index, x, y = vertex_struct.unpack(out)
assert index == (n-1) and int(x) == n and int(y) == (n+1)
if __name__ == '__main__':
main()
这是问题评论中的the code。对于我的计算机上的大n
值,它可以正常运行:
import struct, sys
from subprocess import Popen, PIPE
from threading import Thread
def pack(vertices, n):
yield struct.pack('i', n)
s = struct.Struct('i f f')
for v in vertices:
yield s.pack(*v)
def write(output_file, chunks):
for chunk in chunks:
output_file.write(chunk)
output_file.close()
def main():
try: n = int(sys.argv[1])
except IndexError:
n = 100
vertices = ((i,i+1,i+2) for i in range(n))
p = Popen(["./echo_vertices", "random", "arg"], stdin=PIPE, stdout=PIPE)
Thread(target=write, args=[p.stdin, pack(vertices, n)]).start()
for line in iter(p.stdout.readline, b''):
pass
p.stdout.close()
sys.stdout.buffer.write(line)
p.wait()
if __name__ == '__main__':
main()
问:我真的不明白这个包 函数(我知道收益率回报 一个可迭代的可迭代对象 只有一次,但在你的代码中 使用2产量,所以我不明白它 回报。
pack()
是一个生成器。生成器不能像你描述的那样工作,例如:
>>> def f():
... yield 1
... yield 2
...
>>> for i in f():
... print(i)
...
1
2
注意每个yield
都会产生一个值。
>>> def g(n):
... for i in range(n):
... yield i
...
>>> list(g(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
这里yield
只出现在文本中一次,但每次执行10次,每次产生一个值(在这种情况下为整数)。请参阅Python教程中的Generators。 "Generator Tricks for Systems Programmers"包含有关如何使用从简单到高级用法的生成器的多个示例。
问:另外我不知道是什么 (* v)表示第10行
s.pack(*v)
使用argument unpacking调用pack
方法:
>>> def h(a, b):
... print(a, b)
...
>>> h(*[1, 'a'])
1 a
>>> h(*range(2))
0 1
>>> h(0, 1)
0 1
问:我不明白 第25行中的线程工作,
Thread(target=write, args=[p.stdin, pack(vertices, n)]).start()
此行启动一个新线程,该线程使用write()
关键字参数(即args
和output_file=p.stdin
)中的参数调用chunks=pack(vertices, n)
函数。在这种情况下,write()
函数等同于:
p.stdin.write(struct.pack('i', n))
p.stdin.write(s.pack(0, 1, 2))
p.stdin.write(s.pack(1, 2, 3))
...
p.stdin.write(s.pack(n-1, n, n+1))
p.stdin.close()
之后线程退出。
问: ......等等 程序的读取输出..它 不存储在变量中,是吗?
整个输出不存储在任何地方。代码:
for line in iter(p.stdout.readline, b''):
pass
逐行从p.stdout
读取,直到.readline()
返回空字符串b''
并将当前行存储在line
变量中(请参阅iter()
文档)。所以:
sys.stdout.buffer.write(line)
只打印输出的最后一行。
问: 1)启动线程后, python脚本等待它完成, 正确?
不,主线程退出。启动的线程不是守护进程。它一直运行直到它完成,即脚本(程序)在完成之前不会退出。
问: 2)我明白你的阅读方式 从C程序的标准输出,但我 当你开始它时不要得到.Afa i 理解,用写函数我们 写入缓冲区(或类似的东西) ram中的文件)我们想要的数据,和 当我们运行c程序时,它可以读取 从它我们写的数据。但是当我们 在你的代码中启动C程序? :)
C程序由p = Popen(...)
启动。
p.stdin.write()
写入C程序的stdin
(中间有多个缓冲区,但我们暂时可以忘记它)。该过程与以下内容相同:
$ echo abc | some_program
问: 3)最后一件事:为什么要等待 P +有一个警告 http://docs.python.org/library/subprocess.html?#subprocess.Popen.wait
对于提供的C代码,不必在单独的线程中写入p.stdin
。我完全使用线程来避免警告中描述的情况,即C程序在脚本完成写入stdin之前产生足够的输出(你的C代码在完成读取之前没有写任何东西,所以线程不是必需的)。 / p>
换句话说,p.wait()
在这种情况下是安全的。
没有来自C程序的p.wait()
stderr输出可能会丢失。虽然我只能在the scripts的jython上重现stderr损失。然而,对于提供的C代码,它并不重要,因为它没有写入stderr任何东西。