內(nèi)存映射mmap

什么是mmap<a id="sec-1" name="sec-1"></a>

通常在Unix系統(tǒng)里有兩種操作的數(shù)據(jù)類型:內(nèi)存地址和流文件(stream)。通過操作內(nèi)存地址的方法涉及的操作有:pointers, malloc/free之類,而操作流文件涉及的方法有read/write/seek等系統(tǒng)調(diào)用或者send/recv/etc等socket操作。而mmap提供了結(jié)合上述兩種類型的操作方式。簡(jiǎn)單來講,mmap可以創(chuàng)建一個(gè)內(nèi)存映射(memory-mapped)類型的文件,可以直接在內(nèi)存操作文件,而不需要使用通常的read,wirte這些系統(tǒng)I/O調(diào)用。這樣的好處是避免了操作文件是頻繁地系統(tǒng)調(diào)用。

使用方法<a id="sec-2" name="sec-2"></a>

內(nèi)存映射(memory-mapped)可以像字符串和文件對(duì)象一樣操作,通過 mmap 來創(chuàng)建。
例子中采用的hello.txt文件如下:

Hello, i am Nisen,
Nice to meet you!
Goodbye.

mmap構(gòu)造器的格式<a id="sec-2-1" name="sec-2-1"></a>

# Unix version
class mmap.mmap(fileno, length[, flags[, prot[, access[, offset]]]])

# Windows version
class mmap.mmap(fileno, length[, tagname[, access[, offset]]])

fileno是流文件的描述符,length指定映射文件到內(nèi)存的bytes的長(zhǎng)度,設(shè)置為0的話代表全部。Unix接口中的flags指定這個(gè)創(chuàng)建出來的mapping是否對(duì)創(chuàng)建的進(jìn)程私有,默認(rèn)是共享的。prot和access指定需要的內(nèi)存保護(hù)(讀寫相關(guān)),其它參數(shù)的含義可以參照文檔
接下來讓我們采用Unix的接口,做些實(shí)驗(yàn)吧。

例子1<a id="sec-2-2" name="sec-2-2"></a>

import mmap

with open('hello.txt', 'r') as f:
    m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
    print m.readline()
    m.close()

運(yùn)行的結(jié)果如下:

Hello, i am Nisen,

python3.2以后mmap支持用with的方式操作

# New in version 3.2: Context manager support.
with open('hello.txt', 'r') as f:
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
        print('First 10 bytes via read :', m.read(10))
        print('First 10 bytes via slice:', m[:10])

運(yùn)行后的結(jié)果

python3 test.py
First 10 bytes via read : b'Hello, i am Nisen,\nNice to meet you!\nGoodbye.\n'
First 10 bytes via slice: b'Hello, i a'

例子2<a id="sec-2-3" name="sec-2-3"></a>

常見的方法如下

with open('hello.txt', 'r+') as f:
    # 指定訪問權(quán)限為write, 一共有3種權(quán)限指定:ACCESS_READ, ACCESS_WRITE, ACCESS_COPY
    m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_WRITE)

    # 輸出一行
    print m.readline()

    # 指針重置
    m.seek(0)

    # 查找"Nisen"出現(xiàn)的第一個(gè)地方,返回索引
    index = m.find('Nisen')
    print index

    m.seek(0)

    # 直接修改內(nèi)容
    m[index: index+5] = "Rubby"

    # 將內(nèi)存中的修改存到磁盤中的文件上
    m.flush()

    m.seek(0)
    print m.readline()

    # 關(guān)閉內(nèi)存映射文件
    m.close()

運(yùn)行結(jié)果如下:

? python test2.py
Hello, i am Nisen,

12
Hello, i am Rubby,

其它<a id="sec-3" name="sec-3"></a>

  1. mmap的read()方法在python3.3開始可以接受空參數(shù),表示讀取文件所有的內(nèi)容
  2. 在創(chuàng)建mmap對(duì)象指定權(quán)限的時(shí)候,注意本來文件描述符擁有的權(quán)限。如果使用open()打開文件的權(quán)限指定了'r', 用mmap創(chuàng)建映射對(duì)象時(shí)指定 ACCESS_WRITE ,那么會(huì)報(bào) Permission denied 的錯(cuò)誤
  3. 關(guān)于文件打開模式"r+"和"w+"的用法可以參考這里這里
  4. 在多線程編程時(shí),如果多個(gè)線程以只讀的方式訪問同一個(gè)文件,那么可以采用mmap創(chuàng)一個(gè)映射對(duì)象來減少內(nèi)存的使用提升性能
  5. mmap會(huì)將文件對(duì)象一次讀取到連續(xù)內(nèi)存空間上,如果文件過大導(dǎo)致找不到可用的內(nèi)存空間,那么創(chuàng)建這個(gè)映射對(duì)象將會(huì)失敗
  6. mmap加快文件操作的例子可以參照這里

參考資料<a id="sec-4" name="sec-4"></a>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容