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

时间:2017-07-19 23:06:46

标签: python ctypes shared-memory

有很多示例显示如何将单个变量甚至单个结构成员写入共享内存,但有没有办法将整个结构放入共享内存,以便您可以简单地操作结构来更新共享内存?

这是我到目前为止所做的一个例子(在我的实际程序中 - 结构中有超过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)

...然后会更新共享内存。可能的?

1 个答案:

答案 0 :(得分:1)

正如@eryksun在问题的第一条评论中指出的那样,您可以使用ctypes.from_buffer与mmap缓冲区GenericData共享ctypes结构buff。 @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()