如何在python中为共享内存编写完整的结构?

如何在python中为共享内存编写完整的结构?,python,ctypes,shared-memory,Python,Ctypes,Shared Memory,有很多例子展示了如何将单个变量甚至结构的单个成员写入共享内存,但是有没有一种方法可以将整个结构放入共享内存中,这样您就可以简单地操纵结构来更新共享内存 这是我目前正在做的一个例子(在我的实际程序中-结构中有50多个字段-到我完成时可能有100多个字段)。它每隔0.05秒用x、y、z坐标更新共享内存。当它在运行时,它在每一步都打包一个新的结构,并将整个过程写入共享内存——这对我来说似乎效率低下 import mmap import struct import ctypes import time

有很多例子展示了如何将单个变量甚至结构的单个成员写入共享内存,但是有没有一种方法可以将整个结构放入共享内存中,这样您就可以简单地操纵结构来更新共享内存

这是我目前正在做的一个例子(在我的实际程序中-结构中有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()
我知道我可以在共享内存文件中创建变量到位置的映射,但是有这么多字段,这有点麻烦

我认为struct可以是缓冲区(或映射到缓冲区),只需设置data.PosX,共享内存就会更新。这可能吗?有没有办法让这更有效?我关心的是struct.pack_in line

我想这样做是可以做到的:

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 buffer
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()

你非常非常接近。您是否在ctypes教程和参考中搜索了“from_buffer”?它非常简单:
data=GenericData.from_buffer(buff)
fileno
应该是-1来映射匿名内存。在Windows上,mmap允许0执行此操作,即使0是有效的文件描述符。但是,在将来的版本中,它可能会更新为不推荐在Windows上使用0。@eryksun:谢谢!我知道我离得很近-不知道我离得那么近!另外,感谢您对文件描述符的0与-1的说明。你想提供一个正式的答案,让我接受吗?(否则,我会回答自己并引用你的话)