2017-07-19 77 views
1

有大量的例子展示瞭如何將單個變量或結構的單個成員寫入共享內存,但是有沒有辦法將整個結構放入共享內存中,以便您可以簡單地操作結構來更新共享內存?你如何寫一個完整的結構到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) 

...這將隨後更新共享內存。可能?

+1

你是如此非常,非常接近。你有沒有搜索「from_buffer」的ctypes教程和參考?它非常簡單:'data = GenericData.from_buffer(buff)'。 – eryksun

+0

'fileno'應該是-1來映射匿名內存。在Windows上,mmap允許爲0,即使0是有效的文件描述符。但是,在未來的版本中,它可能會更新爲在Windows上使用0棄用。 – eryksun

+0

@eryksun:謝謝!我知道我很接近 - 不知道我是那麼接近!另外,感謝您對文件描述符的清晰度0和-1。你想提供一個正式的答案,所以我可以接受它嗎? (否則,我會回答自己並引用你) –

回答

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