在Python中创建查找表,写入可被C程序读取的二进制文件
我需要创建一个查找表,这个表在应用中非常重要,因为速度和效率都很关键。这个表会存储时间值,这些时间值是以对数方式分布的,也就是说每个数量级都有相同数量的时间步骤。每个时间值会指向一个波长值的数组,而这些波长值都有一个相关的强度值。就像这样:
t lambda I
0.0001 -> 0.01 -> 100
. 0.02 -> 300
. . .
. . .
. .
0.0002 -> 0.01 -> 200
. 0.02 -> 400
. . .
. . .
. .
等等……
在一些C语言的代码中,会有一个函数接收时间和波长,然后从表中查找对应的强度值。生成正确强度的函数计算量很大,所以我选择使用查找表。我要把这个查找表写入一个二进制文件,因为这个文件会在计算集群的多个节点之间频繁加载和卸载到内存中。由于我对查找表不太熟悉,我想知道实现这个的最佳方法是什么(也就是最快和最有效的方式)。
另外,是否可以从在Python中创建的数据结构写入二进制文件,然后在C中读取?这对我的特定应用会非常有用,因为我已经在使用一些Python代码来生成表中的值。
1 个回答
你可以使用 struct
模块,特别是 struct.pack
来把 Python 中的数据转换成一串二进制数据,然后你可以把这些数据写入文件。
访问数据的最有效方法取决于具体情况。如果你在所有时间值中使用相同范围的 lambda 值,并且时间间隔总是相同的,那么你就知道每个时间点的强度数组的长度。在这种情况下,你可以这样说:
offset = ((time - 0.001)/0.001 * amount_of_intensities + (lambda - 0.01)/0.01)
然后使用这个偏移量来创建一个指针。这假设你已经把二进制文件读入内存,并且创建了一个正确类型的指针。
下面是一个示例(在 IPython 中):
In [1]: import numpy as np
In [2]: data = np.random.random(20)
In [3]: data
Out[3]:
array([ 0.40184104, 0.60411243, 0.52083848, 0.50300288, 0.14613242,
0.39876911, 0.16157968, 0.70979254, 0.65662686, 0.14884378,
0.65650842, 0.40906677, 0.3027295 , 0.26070303, 0.82051509,
0.96337179, 0.34622595, 0.08532211, 0.65079174, 0.68009011])
In [4]: import struct
In [5]: struct.pack('{}d'.format(len(data)), *data)
Out[5]: 'f\xf9\x80y\xc3\xb7\xd9?\xe2x\x92\x99\xe3T\xe3?0vCt\xb5\xaa\xe0?7\xfcJ|\x99\x18\xe0?X\xf5l\x8ew\xb4\xc2?b\x9c\xd1\xden\x85\xd9?\xc4\x0c\xad\x9d\xa4\xae\xc4?\xae\xc3\xbe\xd7\x9e\xb6\xe6?\xd5\xf3\xebV\x16\x03\xe5?\x14J\x9a$P\r\xc3?p\xd4t\xf3\x1d\x02\xe5?\xfe\tUg&.\xda?\xf4hV\x91\xeb_\xd3?@FL\xc0[\xaf\xd0?$\xbe\x08\xda\xa8A\xea?\xf3\x93\xcb\x11\xf1\xd3\xee?\xce\x9e\xd9\xe7\x90(\xd6?\x10\xd2\x12c\xab\xd7\xb5?f\xac\x124I\xd3\xe4?}\x95\x1cSL\xc3\xe5?'
我使用 numpy 模块是为了方便。用浮点数列表也同样有效。
我们从内到外分析最后一行。格式表达式给出:
In [9]: '{}d'.format(len(data))
Out[9]: '20d'
这意味着我们想要生成一个包含 20 个 d
值的字符串。这里的 d
是 格式字符,表示一个 IEEE 754 双精度浮点数。
所以我们实际上有:
struct.pack('20d', *data)
在 data
前面的 *
操作符表示“解包这个列表”。
请注意,二进制数字通常在不同的硬件平台之间不兼容(例如,intel x86 和 ARM)。
一旦你有了这个大的二进制数字数组,你可以直接把它写入文件。
在 C 语言中,打开文件并将整个内容读入一块内存中。然后创建一个正确类型的指针指向那块内存的开头,这样就可以开始使用了。