2017-07-19 71 views
1

単一変数や構造体の個々のメンバーを共有メモリに書き込む方法を示す例はたくさんありますが、構造体全体を共有メモリに入れて共有メモリを更新するために単純に構造体を操作できる方法はありますか?Pythonで共有メモリに完全な構造体を書く方法はありますか?

これは私がこれまで行っていることの例です(私の実際のプログラムでは、構造体に50以上のフィールドがあります。 x、y、z座標で共有メモリを0.05秒ごとに更新します。それが座っているように動作しますが、それはすべてのステップで新しい構造体を詰め込み、すべてを共有メモリに書き込んでいます。これは私にとって非効率的です。

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

あなたはとてもとても、非常に接近しています。あなたはctypesチュートリアルと "from_buffer"のリファレンスを検索しましたか?これは本当に単純です: 'data = GenericData.from_buffer(buff)'。 – eryksun

+0

'fileno'は匿名メモリをマッピングするために-1になります。 Windowsでは、0が有効なファイル記述子であっても、mmapはこれを0にします。ただし、将来のバージョンでは、Windowsで0を使用して非推奨に更新される可能性があります。 – eryksun

+0

@eryksun:ありがとう!私は私が近くにいることを知っていた - 私はそれが近いことを知らなかった!また、ファイルディスクリプタの0と-1についての明確さについてもありがとうございます。私はそれを受け入れることができるように正式な回答を提供したいですか? (そうでなければ、私は自分自身に答えて、あなたを引用します) –

答えて

1

@eryksunは質問の最初のコメントで指摘したように、ctypes.from_bufferを使用して、ctypes構造体GenericDataをmmapバッファ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() 
関連する問題