python共享內存實現進程通信
1.概述
共享內存可以說是最有用的進程間通信方式.兩個不同的進程共享內存的意思是:同一塊物理內存被映射到兩個進程的各自的進程地址空間.一個進程可以及時看到另一個進程對共享內存的更新,反之亦然.採用共享內存通信的一個顯而易見的好處效率高,因為進程可以直接讀寫內存,而不需要任何數據的複製.對於向管道和消息隊列等通信等方式,則需要在內核和用戶空間進行四次的數據複製,而共享內存則只需要兩次數據複製:一次從輸入文件到共享內存區,另一個從共享內存區到輸出文件.實際上,進程之間在共享內存時,並不總是讀寫少量數據後就解除映射,有新的通信時,再重新建立共享內存區域.而是保持共享區域,知道通信完畢為止,這樣,數據內容就一直保存在共享內存中,並沒有寫迴文件.共享內存中的內容往往是在解除映射時才寫迴文件的.因此,採用共享內存的通信方式效率非常高.
mmap系統調用是的是的進程間通過映射同一個普通文件實現共享內存.普通文件被映射到進程地址空間後,進程可以向像訪問普通內存一樣對文件進行訪問,不必再調用read,write等操作.與mmap系統調用配合使用的系統調用還有munmap,msync等. 實際上,mmap系統調用並不是完全為了用於共享內存而設計的.它本身提供了不同於一般對普通文件的訪問方式,是進程可以像讀寫內存一樣對普通文件操作.而Posix或System V的共享內存則是純粹用於共享內存的,當然mmap實現共享內存也是主要應用之一.
2. python mmap模塊詳解
在python中,mmap.mmap()的函數實現在windows和linux上是不一樣的,但實現api介面函數很相似,下面以mmap的windows實現為例說明:
mmap.mmap(fileno, length[, tagname[, access[, offset]]])
fileno:the file handle fileno, 文件描述符
length:共享內存的大小
tagname: 共享內存區域的名字,可以理解為id
access:
ACCESS_READ: 只能讀,如果執行寫操作,raises a TypeError exception
ACCESS_WRITE: 可讀可寫
ACCESS_COPY: 可讀可寫,但不更新到文件中去
函數列表
mmap.close() 斷開映射關係
mmap.find(string[, start[, end]]):返回第一個string的索引,否則返回-1
mmap.move(dest, src, count): 移動count大小的內容從src到dest
mmap.read(num): 根據文件指針的位置兌取num個位元組的內容,更新文件指針的位置
mmap.read_byte():讀取當前字元,更新文件指針位置
mmap.readline():Returns a single line, starting at the current file position and up to the next newline.從當前位置到下一行位置的所有內容
mmap.resize(newsize):Resizes the map and the underlying file,改變映射內存與文件大小
mmap.rfind(string[, start[, end]]): 返回最後一個string的索引
mmap.seek(pos[, whence]): 設置文件指針的位置
mmap.size(): 返回共享內存的大小
mmap.tell():返回當前指針的位置
mmap.write(string):從當前指針位置開始寫入string
mmap.write_byte(byte): Write the single-character string byte into memory at the current position of the file pointer; the file position is advanced by 1.
3.基於mmap和json實現內存共享
ObjectMmap繼承自mmap,結合json實現python obj的共享
jsonwrite(obj): 將可json序列化的obj對象寫入共享內存
jsonread_master():主進程獲取內存內容
jsonread_follower(): 從進程獲取內存內容
自定義的jsonmmap模塊:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import mmap
import json
class ObjectMmap(mmap.mmap):
def __init__(self, fileno=-1, length=1024, access=mmap.ACCESS_WRITE, tagname=share_mmap):
super(ObjectMmap, self).__init__(self, fileno, length, access=access, tagname=tagname)
self.length = length
self.access = access
self.tagname = tagname
def jsonwrite(self, obj):
try:
self.obj = obj
self.seek(0)
obj_str = json.dumps(obj)
obj_len = len(obj_str)
content = str(obj_len) + ":" + obj_str
self.write(content)
self.contentbegin = len(str(obj_len)) + 1
self.contentend = self.tell()
self.contentlength = self.contentend - self.contentbegin
return True
except Exception, e:
return False
def jsonread_master(self):
try:
self.seek(self.contentbegin)
content = self.read(self.contentlength)
obj = json.loads(content)
self.obj = obj
return obj
except Exception, e:
if self.obj:
return self.obj
else:
return None
def jsonread_follower(self):
try:
self.seek(0)
index = self.find(":")
if index != -1:
head = self.read(index + 1)
contentlength = int(head[:-1])
content = self.read(contentlength)
obj = json.loads(content)
self.obj = obj
return obj
else:
return None
except Exception, e:
if self.obj:
return self.obj
else:
return None
4.舉例
主進程:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import mmap
from jsonmmap import ObjectMmap
import random
def main():
mm = ObjectMmap(-1, 1024*1024, access=mmap.ACCESS_WRITE, tagname=share_mmap)
while True:
length = random.randint(1, 100)
p = range(length)
mm.jsonwrite(p)
print * * 30
print mm.jsonread_master()
if __name__ == __main__:
main()
從進程:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import mmap
from jsonmmap import ObjectMmap
import time
def main():
mm = ObjectMmap(-1, 1024*1024, access=mmap.ACCESS_READ, tagname=share_mmap)
while True:
print * * 30
print mm.jsonread_follower()
if __name__ == __main__:
main()
5.應用場景
主進程+多個從進程,主進程負責管理多個從進程,主從進程共享一個可序列化json對象,譬如說共享配置; 主進程才具備許可權去修改配置,從進程僅僅具備訪問許可權。
import mmap
mmap_file = None##從內存中讀取信息,def read_mmap_info(): global mmap_file mmap_file.seek(0) ##把二進位轉換為字元串 info_str=mmap_file.read().translate(None, bx00).decode() print(info_str)##如果內存中沒有對應信息,則向內存中寫信息以供下次調用使用def get_mmap_info(): global mmap_file ##第二個參數1024是設定的內存大小,單位:位元組。如果內容較多,可以調大一點 mmap_file = mmap.mmap(-1, 1024, access = mmap.ACCESS_WRITE, tagname = share_mmap) ##讀取有效比特數,不包括空比特 cnt=mmap_file.read_byte() if cnt==0: print("Load data to memory") mmap_file = mmap.mmap(0, 1024, access = mmap.ACCESS_WRITE, tagname = share_mmap) mmap_file.write(b"This is the test data") else : print("The data is in memory") read_mmap_info()##修改內存塊中的數據def reset_mmp_info: global mmap_file mmap_file.seek(0) mmap_file.write(bx00) mmap_file.write(b"Load data to memory agine")if __name__=="__main__": get_mmap_info()說明:如果是使用python自帶的IDE,請重新打開一次此文件運行測試數據裝載到內存後的結果簡單進程通信案例
#########################################################
#writer
import win32event as w32e
import mmapfile as mmf
#hEvent = w32e.OpenEvent(w32e.EVENT_ALL_ACCESS , 0 , "KaiMemEvent") #"Global\JmdebuggerEvent"
pyMm = mmf.mmapfile(None , "KaiMem" ,1024)
hEvent = 1
if hEvent != None and pyMm != None:
#w32e.SetEvent(hEvent)
pyMm.write("hello world again!");
#############################################################
#reader
import win32event as w32e
import win32api as wapi
import mmapfile as mmf
#hEvent = w32e.CreateEvent(w32e.EVENT_ALL_ACCESS , 0 , 0 , "KaiMemEvent") #
#system_info=wapi.GetSystemInfo()
#page_size=system_info[1]
pyMm = mmf.mmapfile(None , "KaiMem" ,1024 )
hEvent = 1
if hEvent != None and pyMm != None :
#w32e.WaitForSingleObject(hEvent , -1)
buf = pyMm.read(22)
print buf
#wapi.CloseHandle(hEvent)
pyMm.close()
推薦閱讀:
※人工智慧時代,為什麼大家看好Python?
※邏輯回歸3(代碼解釋)
※條件語句
※Excel x Python的奇妙反應
※【翻譯】《利用Python進行數據分析·第2版》第5章(上)pandas入門