如何在 python 中将完整结构写入共享内存?
How do you write a full struct to shared memory in python?
有很多示例说明如何将单个变量甚至结构的单个成员写入共享内存,但是有没有办法将整个结构放入共享内存以便您可以简单地操作结构来更新共享内存?
这是我目前所做的一个示例(在我的实际程序中 - 结构中有 50 多个字段 - 到我完成时可能超过 100 个)。它每 0.05 秒用 x、y、z 坐标更新共享内存。虽然它按原样工作,但它在每一步都打包一个新结构并将整个内容写入共享内存——这对我来说似乎效率低下。
import mmap
import struct
import ctypes
import time
import random
class GenericData(ctypes.Structure):
_pack_ = 4
_fields_ = [
('PosX', ctypes.c_float),
('PosY', ctypes.c_float),
('PosZ', ctypes.c_float),
]
# fake getters:
def getX():
return random.random()*10
getZ = getY = getX
def main():
buff = mmap.mmap(0, ctypes.sizeof(GenericData), "$MyTag$")
data = GenericData()
fmt = ''.join([f[1]._type_ for f in data._fields_])
while (1):
data.PosX = getX()
data.PosY = getY()
data.PosZ = getZ()
print "Setting %f, %f, %f " % (data.PosX, data.PosY, data.PosZ)
struct.pack_into(fmt, buff, 0, *[getattr(data,field) for field,typ in data._fields_])
time.sleep(0.05)
if __name__ == "__main__":
main()
我知道我可以创建变量到共享内存文件中位置的映射,但是有这么多字段,这有点笨拙。
我认为该结构可以是缓冲区(或映射到缓冲区),只需设置 data.PosX,即可更新共享内存。这可能吗?有什么办法可以提高效率吗? struct.pack_into 行与我有关。
我认为可以做这样的事情:
buff = mmap.mmap(0, ctypes.sizeof(GenericData), "$MyTag$")
data = from_buffer(buff, GenericData)
while (1):
data.posX = getX()
data.posY = getY()
data.posZ = getZ()
time.sleep(0.05)
...然后将更新共享内存。可能吗?
正如@eryksun 在问题的第一条评论中指出的,您可以使用 ctypes.from_buffer
与 mmap 缓冲区 buff
共享 ctypes 结构 GenericData
。 @eryksun 还指出,虽然 Windows 允许 0
作为文件描述符来映射匿名内存,但 -1
是正确的值——如文档中所述。
有了这个,这里有一个工作示例,经过调整以包括@eryksun 的回答:
import ctypes
import mmap
import time
import math
class GenericData(ctypes.Structure):
_pack_ = 4
_fields_ = [
('PosX', ctypes.c_float),
('PosY', ctypes.c_float),
('PosZ', ctypes.c_float),
]
# fake getters:
def getX():
return random.random()*10
getZ = getY = getX
def main():
buff = mmap.mmap(-1, ctypes.sizeof(GenericData), "$MyTag$")
data = GenericData.from_buffer(buff)
for fname, ftype in data._fields_:
setattr(data, fname, 0)
count = 0
while (1):
data.PosX = getX()
data.PosY = getY()
data.PosZ = getZ()
print ("Setting %f, %f, %f " % (data.PosX, data.PosY, data.PosZ))
count += 1
time.sleep(0.05)
if __name__ == "__main__":
main()
有很多示例说明如何将单个变量甚至结构的单个成员写入共享内存,但是有没有办法将整个结构放入共享内存以便您可以简单地操作结构来更新共享内存?
这是我目前所做的一个示例(在我的实际程序中 - 结构中有 50 多个字段 - 到我完成时可能超过 100 个)。它每 0.05 秒用 x、y、z 坐标更新共享内存。虽然它按原样工作,但它在每一步都打包一个新结构并将整个内容写入共享内存——这对我来说似乎效率低下。
import mmap
import struct
import ctypes
import time
import random
class GenericData(ctypes.Structure):
_pack_ = 4
_fields_ = [
('PosX', ctypes.c_float),
('PosY', ctypes.c_float),
('PosZ', ctypes.c_float),
]
# fake getters:
def getX():
return random.random()*10
getZ = getY = getX
def main():
buff = mmap.mmap(0, ctypes.sizeof(GenericData), "$MyTag$")
data = GenericData()
fmt = ''.join([f[1]._type_ for f in data._fields_])
while (1):
data.PosX = getX()
data.PosY = getY()
data.PosZ = getZ()
print "Setting %f, %f, %f " % (data.PosX, data.PosY, data.PosZ)
struct.pack_into(fmt, buff, 0, *[getattr(data,field) for field,typ in data._fields_])
time.sleep(0.05)
if __name__ == "__main__":
main()
我知道我可以创建变量到共享内存文件中位置的映射,但是有这么多字段,这有点笨拙。
我认为该结构可以是缓冲区(或映射到缓冲区),只需设置 data.PosX,即可更新共享内存。这可能吗?有什么办法可以提高效率吗? struct.pack_into 行与我有关。
我认为可以做这样的事情:
buff = mmap.mmap(0, ctypes.sizeof(GenericData), "$MyTag$")
data = from_buffer(buff, GenericData)
while (1):
data.posX = getX()
data.posY = getY()
data.posZ = getZ()
time.sleep(0.05)
...然后将更新共享内存。可能吗?
正如@eryksun 在问题的第一条评论中指出的,您可以使用 ctypes.from_buffer
与 mmap 缓冲区 buff
共享 ctypes 结构 GenericData
。 @eryksun 还指出,虽然 Windows 允许 0
作为文件描述符来映射匿名内存,但 -1
是正确的值——如文档中所述。
有了这个,这里有一个工作示例,经过调整以包括@eryksun 的回答:
import ctypes
import mmap
import time
import math
class GenericData(ctypes.Structure):
_pack_ = 4
_fields_ = [
('PosX', ctypes.c_float),
('PosY', ctypes.c_float),
('PosZ', ctypes.c_float),
]
# fake getters:
def getX():
return random.random()*10
getZ = getY = getX
def main():
buff = mmap.mmap(-1, ctypes.sizeof(GenericData), "$MyTag$")
data = GenericData.from_buffer(buff)
for fname, ftype in data._fields_:
setattr(data, fname, 0)
count = 0
while (1):
data.PosX = getX()
data.PosY = getY()
data.PosZ = getZ()
print ("Setting %f, %f, %f " % (data.PosX, data.PosY, data.PosZ))
count += 1
time.sleep(0.05)
if __name__ == "__main__":
main()