Python自帶的memoryview可以說是一個高效的內存操作工具,可以讓我們更好地處理二進制數據。在本文中,我們將從多個方面深入探討memoryview,讓我們一步一步去揭開它的神秘面紗。
一、memoryview是什麼?
1、memoryview的概念
在Python中,memoryview是一個在不複製內容的情況下訪問內存的工具。它是一個內存切片的概念,它允許我們在不複製數據的情況下訪問和操作二進制數據。
2、memoryview的定義方法
# 定義方法 mv = memoryview(byte_array)
在上面的代碼中,byte_array可以是bytes對象或bytearray對象。通過memoryview實例化一個對象後,它將提供一些方法來訪問底層數據,例如mv[i]和mv[i:j](切片)。
3、memoryview的內存模型
創建一個memoryview對象時,Python存儲器資源是以numpyndarray的方式進行管理的。它實際上是兩個標準C結構的Python對象:
- Py_buffer(也稱為Py_buffer結構體),它定義了Numpy的ndarray存儲器結構,並描述了訪問這個存儲器需要的所有信息。
- MemoryViewObject,實質上是Python內部的一個主語義對象,它實現了一個memoryview對象實例。
二、memoryview在Python中有哪些用途?
1、memoryview優勢
對於Python內置的數組數據類型(如NDArray和PyArrayObject)來說,memoryview的一個顯著優點是它可以利用Python的GIL(全局解釋器鎖)被並行修改,而不會破壞數據的完整性和一致性。
2、memoryview的用途
- Memoryview可以提高Python程序執行效率,因為它能夠比較整塊地存儲和處理二進制數據。
- Memoryview特別適用於塊處理文件或網絡數據流。
- Memoryview對於多個並發任務處理二進制數據也特別有用,可以實現數據的並行訪問而無需加鎖。
三、常用的memoryview操作方法
1、memoryview選取
memoryview允許我們像操作普通的Python序列(例如list和tuple)一樣進行切片操作。但是,與普通的Python序列不同的是,memoryview的切片並不會創建新的數據副本,而是直接返回底層數據的一個視圖。
# 創建bytearray bytearray_test = bytearray(b'abcd') # 通過memoryview選取子對象 mv_test = memoryview(bytearray_test) sub_mv_test = mv_test[1:3] print(sub_mv_test) # # 修改對象 sub_mv_test[:] = b'xy' print(mv_test.tobytes()) # b'axyd'
2、memoryview.cast
通過memoryview對象可以提供對同一個內存區域的不同切片視圖,還可以使用memoryview.cast方法創建一個對象的內存視圖。
import numpy as np # 創建一個int8數組 array_test = np.zeros((3,), dtype=np.int8) array_test_pointer = memoryview(array_test) # 將int8數組地址轉換成int32數組地址,並創建memoryview int32_array_pointer = array_test_pointer.cast('i') print(int32_array_pointer.format) # 'i' print(int32_array_pointer.itemsize) # 4 print(int32_array_pointer.shape) # (3,)
3、memoryview.bytes_per_element
bytes_per_element是memoryview對象的一個屬性,返回單個元素的大小(以字節為單位)。
array_bytes = bytearray(b'123456') array_pointer = memoryview(array_bytes) print(array_pointer.bytes_per_element) # 1
四、memoryview與USB設備交互的示例
下面將演示如何利用memoryview和PyUSB連接USB設備,讀取USB設備返回的二進制數據並進行處理。
import usb.core import usb.util # 查找USB設備 device = usb.core.find(idVendor=0x1234, idProduct=0x5678) # 設置配置並進行USB設備輸出流的連接 if device is not None: endpoint_out = device[0][(0, 0)][0] device.write(endpoint_out, 'test') # 讀取USB設備返回的二進制數據 endpoint_in = device[0][(0, 0)][1] device.read(endpoint_in.bEndpointAddress, endpoint_in.wMaxPacketSize) # 利用memoryview處理返回的二進制數據 response_mv = memoryview(device.read(endpoint_in.bEndpointAddress, endpoint_in.wMaxPacketSize))
五、memoryview的局限性
1、不能被序列化
memoryview對象不能被Python pickle序列化,因為它們是包含底層內存地址和長度信息的指針。這意味着如果需要序列化,必須在調用pickle模塊之前先轉換為bytes或bytearray類型。
2、不能跨進程使用
由於memoryview基於底層內存視圖的概念,因此它們通常只對包含它們的那個Python程序實例可用,而且不能被另一個Python程序實例共享。這也是因為操作系統的Kernal通常不允許一個進程訪問另一個進程的內存。
3、不適用於所有二進制數據類型
雖然memoryview可以處理多種類型的二進制數據(例如bytes對象和numpy數組),但是對於C結構之類的複雜類型,memoryview可能不是一個良好的選擇。這是因為指針操作和內存布局可能存在非常細微的差異,這將使得memoryview無法精確地處理它。
六、結語
通過本文對memoryview的深入剖析,我們了解了它的概念、優勢、用途以及實際應用示例,同時也揭示了它的局限性。對於經常需要處理二進制數據的Python開發人員來說,memoryview無疑是一個非常有用的工具。
原創文章,作者:DMCGM,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/334485.html