推 LiloHuang: 如果要在 Python 內操作資料,資料通常都得做搬動的 08/14 23:35
→ LiloHuang: 我猜你應該是想要做以下的事情...我先把問題簡化 08/14 23:35
→ LiloHuang: 假設使用 addr = ctypes.cdll.msvcrt.malloc(1024) 08/14 23:36
→ LiloHuang: 得到一個記憶體位置為 addr,類似你的GetBufferAddress 08/14 23:36
→ LiloHuang: 如果我先用 memmove(addr, "\xFF\xFF\x00\x00", 4) 08/14 23:36
→ LiloHuang: 此時應該會寫入 4 byte 的資料,考慮 little endian 08/14 23:37
→ LiloHuang: cast(x, POINTER(c_int)).contents.value 會讀出 65535 08/14 23:37
→ LiloHuang: 抱歉上面的 x 是指 addr 的意思,推文實在塞不下 08/14 23:38
→ LiloHuang: 再次更正 x = c_void_p(addr) 08/14 23:39
→ LiloHuang: 使用 c_void_p(addr) 的方式將你的指標塞進去後 08/14 23:40
→ LiloHuang: 就可以用 cast 搭配 contents.value 的方式來做存取了 08/14 23:41
→ dctzeng: 那在python宣告記憶體,把位址傳給dll去處理會省copy嗎? 08/14 23:42
推 LiloHuang: 這樣記憶體就是由 Python runtime 幫你管理 08/14 23:44
→ dctzeng: 例如宣告1MB string 把位址當參數給dll當char* 處理好嗎 08/14 23:44
→ LiloHuang: 至於拷貝看是拷貝什麼,畢竟很多東西都得變 PyObject 08/14 23:44
→ LiloHuang: 可以的呀,正常操作狀況不會一直拷貝那 1MB 的 08/14 23:45
→ dctzeng: 但其實string 不是char*,是硬碟任意資料 fd.Read() 來的 08/14 23:45
→ dctzeng: 就是 fd.Read()讀一坨資料; dll讀一坨資料,兩個相比而已 08/14 23:47
→ LiloHuang: 你可以看看 byref, addressof, cast 這幾個的用法 08/14 23:47
→ LiloHuang: 資料從 Python 跟 C API 做交換,ctypes 會有一些成本 08/14 23:48
→ dctzeng: 只是資料量大而且多thread要長時間跑,很不想額外memcpy 08/14 23:48
→ LiloHuang: 當你東西是使用指標 (也就是我上面的範例) 算快的做法 08/14 23:48
→ LiloHuang: 如果是我寫我會盡量讓 Python runtime 來幫我管記憶體 08/14 23:49
→ LiloHuang: 當然還是得看場合,到底是誰該擺那一塊記憶體... 08/14 23:51
→ LiloHuang: 好比說用 create_string_buffer 來產生 buffer object 08/14 23:52
→ dctzeng: 那1MB會重複一直讀出來是因為那是dll的buffer,會重複更新 08/14 23:54
推 LiloHuang: 不好意思我現在看到你修改後的文章了... 08/14 23:55
→ dctzeng: 喔~ 不會 看到你提一些關鍵字沒用過,google查一查 偷學 08/14 23:56
推 LiloHuang: 那我重新修正,如果你只是想要比較用 c_char_p 就好 08/15 00:08
→ LiloHuang: foo = 'x'*1024*1024*100 # 記憶體耗用 100 MB 左右 08/15 00:09
→ LiloHuang: bar = c_char_p(foo) # 這個動作不會拷貝 100MB 08/15 00:09
→ LiloHuang: ctypes.memmove(bar, "test", 4) # 硬是修改 foo 字串 08/15 00:09
→ LiloHuang: # 雷同於你傳入 DLL 08/15 00:10
→ LiloHuang: print foo[0:10] # 順便再印出 foo 的一部分觀察 08/15 00:10
→ LiloHuang: 以上的 foo 類似於你從 fd.read 讀出的字串結果 08/15 00:11
→ LiloHuang: ctypes.memmove 類似於你帶入 DLL 的部分,試試看囉 08/15 00:12
→ LiloHuang: 可搭配 ProcessExplorer 選 python.exe 觀察記憶體用量 08/15 00:14
我試試 先謝謝
※ 編輯: dctzeng (111.243.146.150), 08/15/2014 00:23:42
推 LiloHuang: 順便回你文章的那個問題,那個寫法應該也不會拷貝資料 08/15 00:41
→ LiloHuang: 至於之所以會出錯的原因是 from_address 是吃 integer 08/15 00:42
→ LiloHuang: 用了 hex 就變成了字串,錯誤訊息是指參數型別不正確 08/15 00:43
→ LiloHuang: 這種做法也是拿一個指標來操作的做法,都相當的快速 08/15 00:44
※ 編輯: dctzeng (111.243.146.150), 08/15/2014 01:06:02