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
后台-插件-广告管理-内容页尾部广告(手机) |