【问题标题】:How do you write a full struct to shared memory in python?如何在 python 中将完整的结构写入共享内存?
【发布时间】:2017-07-19 23:06:45
【问题描述】:

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

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

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

【问题讨论】:

  • 你们非常非常亲近。您是否在 ctypes 教程和参考资料中搜索过“from_buffer”?真的很简单:data = GenericData.from_buffer(buff).
  • fileno 应该为 -1 用于映射匿名内存。在 Windows 上,mmap 为此允许 0,即使 0 是有效的文件描述符。但是,在未来的版本中,它可能会更新为在 Windows 上使用 0 弃用。
  • @eryksun:谢谢!我知道我很接近 - 不知道我有那么接近!另外,感谢您对文件描述符的 0 与 -1 的清晰说明。您想提供官方答案以便我接受吗? (否则,我会自己回答并引用你)

标签: python ctypes shared-memory


【解决方案1】:

正如@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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 2010-11-28
    • 2016-03-17
    • 1970-01-01
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多