程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python - mmap 共享內存

編輯:Python

在程序運行過程中,可能遇到需要進程間或不同平台的語言之間進行信息交互,存在硬盤是一種解決方案但是速度太慢。python的mmap庫提供了共享內存的實踐方案可以完成信息在內存間交互。

簡介

共享內存

內存共享是兩個不同的進程共享內存的意思:同一塊物理內存被映射到兩個進程的各自的進程地址空間。這個物理內存已經被規定了大小(大小一定要比實際寫入的東東大)以及名稱。當需要寫入時,找到內存名稱,然後寫入內存,等需要讀取時候, 首先要知道你要讀取多大(因為物理內存比你要讀取的東東大,全部讀取的話會讀到一些“空”的東西),然後尋找對應名稱的物理塊,然後讀取,就是這麼簡單。

mmap

mmap是一種虛擬內存映射文件的方法,即將一個文件或者其它對象映射到進程的地址空間,實現文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。關於系統中mmap的理論說明可以看百度百科和維基百科說明以及mmap函數介紹,這裡的說明是針對在Python下mmap塊的使用說明。

  • 官網文檔:https://docs.python.org/2/library/mmap.html

使用方法

創建:創建並返回一個 mmap 對象

m = mmap.mmap(fileno, length[, flags[, prot[, access[, offset]]]])
  • fileno: 文件描述符,可以是file對象的fileno()方法,或者來自os.open(),在調用mmap()之前打開文件,不再需要文件時要關閉。
os.O_RDONLY 以只讀的方式打開 Read only
os.O_WRONLY 以只寫的方式打開 Write only
os.O_RDWR 以讀寫的方式打開 Read and write
os.O_APPEND 以追加的方式打開
os.O_CREAT 創建並打開一個新文件
os.O_EXCL os.O_CREAT| os.O_EXCL 如果指定的文件存在,返回錯誤
os.O_TRUNC 打開一個文件並截斷它的長度為零(必須有寫權限)
os.O_BINARY 以二進制模式打開文件(不轉換)
os.O_NOINHERIT 阻止創建一個共享的文件描述符
os.O_SHORT_LIVED
os.O_TEMPORARY 與O_CREAT一起創建臨時文件
os.O_RANDOM 緩存優化,但不限制從磁盤中隨機存取
os.O_SEQUENTIAL 緩存優化,但不限制從磁盤中序列存取
os.O_TEXT 以文本的模式打開文件(轉換)

  • **length:**要映射文件部分的大小(以字節為單位),這個值為0,則映射整個文件,如果大小大於文件當前大小,則擴展這個文件。
  • flags:MAP_PRIVATE:這段內存映射只有本進程可用;mmap.MAP_SHARED:將內存映射和其他進程共享,所有映射了同一文件的進程,都能夠看到其中一個所做的更改;
  • **prot:**mmap.PROT_READ, mmap.PROT_WRITE 和 mmap.PROT_WRITE | mmap.PROT_READ。最後一者的含義是同時可讀可寫。
  • **access:**在mmap中有可選參數access的值有:
ACCESS_READ:讀訪問。
ACCESS_WRITE:寫訪問,默認。
ACCESS_COPY:拷貝訪問,不會把更改寫入到文件,使用flush把更改寫到文件。

對象方法

  • m.close()

關閉 m 對應的文件;

  • m.find(str, start=0)

從 start 下標開始,在 m 中從左往右尋找子串 str 最早出現的下標;

  • m.flush([offset, n])

把 m 中從offset開始的n個字節刷到對應的文件中;

  • m.move(dstoff, srcoff, n)

等於 m[dstoff:dstoff+n] = m[srcoff:srcoff+n],把從 srcoff 開始的 n 個字節復制到從 dstoff 開始的n個字節,可能會覆蓋重疊的部分。

  • m.read(n)

返回一個字符串,從 m 對應的文件中最多讀取 n 個字節,將會把 m 對應文件的位置指針向後移動;

  • m.read_byte()

返回一個1字節長的字符串,從 m 對應的文件中讀1個字節,要是已經到了EOF還調用 read_byte(),則拋出異常 ValueError;

  • m.readline()

返回一個字符串,從 m 對應文件的當前位置到下一個’\n’,當調用 readline() 時文件位於 EOF,則返回空字符串;

  • m.resize(n)

把 m 的長度改為 n,m 的長度和 m 對應文件的長度是獨立的;

  • m.seek(pos, how=0)

同 file 對象的 seek 操作,改變 m 對應的文件的當前位置;

  • m.size()

返回 m 對應文件的長度(不是 m 對象的長度len(m));

  • m.tell()

返回 m 對應文件的當前位置;

  • m.write(str)

把 str 寫到 m 對應文件的當前位置,如果從 m 對應文件的當前位置到 m 結尾剩余的空間不足len(str),則拋出 ValueError;

  • m.write_byte(byte)

把1個字節(對應一個字符)寫到 m 對應文件的當前位置,實際上 m.write_byte(ch) 等於 m.write(ch)。如果 m 對應文件的當前位置在 m 的結尾,也就是 m 對應文件的當前位置到 m 結尾剩余的空間不足1個字節,write() 拋出異常ValueError,而 write_byte() 什麼都不做。

使用示例

寫入數據進共享內存

import ctypes
import mmap # 核心庫
import os
import struct
import numpy as np
# 創建內存映射文件句柄
fd = os.open('tmp/mmaptest', os.O_CREAT | os.O_TRUNC | os.O_RDWR)
# 建立內存緩沖區
# not win32
buf = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE)
# win32
buf = mmap.mmap(fd, 67108864, access = mmap.ACCESS_WRITE)
# 向buf中寫入文件(二進制格式)
f = open('tmp/test2.bmp', 'rb').read()
buf.write(b'abc') # 寫入字符串
buf.write(f) # 寫入文件
# 當前指針位置
buf.tell()
# 移動指針到第11個字節
buf.seek(10)
# 將內存中的信息寫入文件
buf.flush(0, 100)
# 關閉
buf.close()

從共享內存中讀取數據

import mmap
import os
import struct
import cv2
import numpy as nps
# 創建內存映射文件句柄
fd = os.open('share_memory/tmp/mmaptest', os.O_RDONLY)
# 建立內存緩沖區
# not win32
buf = mmap.mmap(fd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_READ)
# win32
buf = mmap.mmap(fd, 67108864, access = mmap.ACCESS_READ)
# 讀取並打印緩沖區中指定區域內存
string_length = 136
string, = struct.unpack('{}s'.format(string_length), buf[:string_length])
print(string)
# 將部分區域轉換為需要的格式並使用(圖像)
np_str = np.fromstring(buf[:string_length], dtype='uint8')
img = cv2.imdecode(np_str, flags=-1)
# 純圖像像素數據(僅需轉換字符串為uint8)即可
data = np.fromstring(buf[:string_length], dtype='uint8')
img = data.reshape([10,10])

代碼運行不會順暢,僅提供使用思路

參考資料

  • https://docs.python.org/2/library/mmap.html
  • https://zhuanlan.zhihu.com/p/166330573
  • https://www.cnblogs.com/zhoujinyi/p/6062907.html

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved