在python中将浮点数列表打包成字节的最快方法

MxL*_*evs 27 python struct python-3.x

我有一个说100k浮点数的列表,我想将其转换为字节缓冲区.

buf = bytes()
for val in floatList:
   buf += struct.pack('f', val)
return buf
Run Code Online (Sandbox Code Playgroud)

这很慢.如何仅使用标准的Python 3.x库使其更快.

agf*_*agf 46

告诉你有struct多少float人.在我的慢速笔记本电脑上,100k浮动大约需要1/100秒.

import random
import struct

floatlist = [random.random() for _ in range(10**5)]
buf = struct.pack('%sf' % len(floatlist), *floatlist)
Run Code Online (Sandbox Code Playgroud)

  • FWIW:使用`array.array`但值得注意的是`array.tobytes()`返回与`struct.pack(...)`相同的内容.因此,可以使用`数组('f`,[...])`并具有`append`,索引器可访问性等.Array.array没有与`list`相同的所有方法,但可能更容易在许多情况下实施. (2认同)

jsb*_*eno 7

您可以使用ctypes,并且具有与C中完全相同的双数组(或浮点数组),而不是将数据保存在列表中.这是一个相当低的水平,但如果您需要出色的表现并且您的列表是固定大小的话,这是一个建议.

您可以double array[100]; 通过执行以下操作在Python中创建C的等效项 :

array = (ctypes.c_double * 100)()
Run Code Online (Sandbox Code Playgroud)

ctypes.c_double * 100表达式为双精度数组生成一个Python类,长100项.要将其连接到文件,您可以使用它buffer来获取其内容:

>>> f = open("bla.dat", "wb")
>>> f.write(buffer(array))
Run Code Online (Sandbox Code Playgroud)

如果你的数据已经在Python列表中,将它打包成一个双数组可能会或者可能不会struct像在Agf接受的答案中那样调用- 我将留下测量哪个更快作为家庭作业,但你需要的所有代码是:

>>> import ctypes
>>> array = (ctypes.c_double * len(floatlist))(*floatlist)
Run Code Online (Sandbox Code Playgroud)

要将其视为字符串,只需执行以下操作:str(buffer(array)) - 这里的一个缺点是您必须处理float size(float vs double)和CPU依赖的float类型 - struct模块可以为您处理这个问题.

最大的好处是,使用float数组,你仍然可以使用元素作为数字,通过访问然后就像它在普通的Python列表中一样,同时随后可以作为平面内存区域使用buffer.


Jon*_*ley 5

几个答案建议

import struct
buf = struct.pack(f'{len(floatlist)}f', *floatlist)
Run Code Online (Sandbox Code Playgroud)

但是使用“ *”不必要的转换floatlist,以一个元组将它传递给前struct.pack。避免这种情况会更快,首先创建一个空缓冲区,然后使用切片分配填充它:

import ctypes
buf = (ctypes.c_double * len(floatlist))()
buf[:] = floatlist
Run Code Online (Sandbox Code Playgroud)

有些人可能可以使用其他性能节省:

  • 您只需再次执行分配即可重用现有缓冲区,而无需创建新缓冲区。
  • 您可以通过分配给适当的切片来修改现有缓冲区的一部分。