您现在的位置是:首页 > 技术教程 正文

Go mmap 文件内存映射

admin 阅读: 2024-03-19
后台-插件-广告管理-内容页头部广告(手机)

Go mmap 文件内存映射

mmap是个很好用的内存映射工具,它可以将文件映射到内存中,可以方便地操作文件。使用mmap的优点是:

  • 内存映射可以使得读写文件的性能更高,因为操作的是内存而不是磁盘。
  • 可以方便地操作文件,不需要再通过文件操作的方式打开读写文件。
  • 方便多线程操作文件。

在这里插入图片描述

优点

mmap 另一个非常重要的特性是:减少内存的拷贝次数。在 linux 系统中,文件的读写操作通常通过 read 和 write 这两个系统调用来实现,这个过程会产生频繁的内存拷贝。比如 read 函数就涉及了 2 次内存拷贝:

  • 操作系统读取磁盘文件到页缓存
  • 从页缓存将数据拷贝到 read 传递的 buf 中
    mmap 只需要一次拷贝。即操作系统读取磁盘文件到页缓存,进程内部直接通过指针方式修改映射的内存。因此 mmap 特别适合读写频繁的场景,既减少了内存拷贝次数,提高效率,又简化了操作。KV数据库 bbolt 就使用了这个方法持久化数据。

例子

package main import ( "fmt" "log" "os" "syscall" "unsafe" ) const defaultMaxFileSize = 1 << 30 // 假设文件最大为 1G const defaultMemMapSize = 128 * (1 << 20) // 假设映射的内存大小为 128M func main() { mmpFile := NewMmpFile("test.txt") defer mmpFile.munmap() defer mmpFile.file.Close() msg := "hello csdn colinrs!" mmpFile.grow(int64(len(msg) * 2)) for i, v := range msg { mmpFile.data[i] = byte(v) } } type MmpFile struct { file *os.File data *[defaultMaxFileSize]byte dataRef []byte } func NewMmpFile(fileName string) *MmpFile { file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0666) if err != nil { log.Fatalf("Open file error: %v", err) } mmpFile := &MmpFile{file: file} mmpFile.mmap() return mmpFile } func _assert(condition bool, msg string, v ...interface{}) { if !condition { panic(fmt.Sprintf(msg, v...)) } } func (mmpFile *MmpFile) mmap() { b, err := syscall.Mmap(int(mmpFile.file.Fd()), 0, defaultMemMapSize, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED) _assert(err == nil, "failed to mmap", err) mmpFile.dataRef = b mmpFile.data = (*[defaultMaxFileSize]byte)(unsafe.Pointer(&b[0])) } func (mmpFile *MmpFile) grow(size int64) { if info, _ := mmpFile.file.Stat(); info.Size() >= size { return } _assert(mmpFile.file.Truncate(size) == nil, "failed to truncate") } func (mmpFile *MmpFile) munmap() { _assert(syscall.Munmap(mmpFile.dataRef) == nil, "failed to munmap") mmpFile.data = nil mmpFile.dataRef = nil }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 遇到 mmp 文件报错为 syscall.Errno=permission denied),
    • 可以参考:syscall.Errno=permission denied)
    • 将读取文件修改为 os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0666)

参考

  • Go Mmap 文件内存映射简明教程
  • 阅读笔记:零拷贝及一些引申内容
标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索