【问题标题】:mmap syscall using Golang for reads使用 Golang 进行读取的 mmap 系统调用
【发布时间】:2017-11-14 16:36:07
【问题描述】:

我不是 Go 不安全包专家 - 我也不是经验丰富的 C 程序员。我正在尝试在 go 中使用 mmap 系统调用读取一个 > 1G 的大文件。我使用 mmap 和 munmap 而不是读、写 I/O 的原因有很多。这不是重点 - 我可以在测试中写入文件,当我从文件中读取时,我可以确定字节长度匹配,但我无法读取此字符串文件的内容:(有人可以建议阅读吗?我需要做的更进一步,这是我为示例测试编写的一些代码:

filename := "/tmp/dd_file.db"
f, err := os.OpenFile(filename, os.O_RDWR, 0666)
defer f.Close()
if err != nil {
    fmt.Printf("error opening file: %v", err)
}
stat, _ := f.Stat()
size := stat.Size()
fmt.Printf("[READ-ONLY] : size was : %+v\n", size)
got := make([]byte, size)
if _, err := f.ReadAt(got, 0); err != nil && err != io.EOF {
    panic(err)
}
want, err := ioutil.ReadFile(filename)
if err != nil {
    fmt.Printf("[READ-ONLY] : ioutil.ReadFile: %v", err)
}
// going to change the file size now, punch in a few things
t := unsafe.Sizeof("")
if err != nil {
    fmt.Println(err)
    os.Exit(1)
}
_, err = f.Seek(int64(t-1), 0)
if err != nil {
    fmt.Println(err)
    os.Exit(1)
}
_, err = f.Write([]byte(" "))
if err != nil {
    fmt.Println(err)
    os.Exit(1)
}
mmap, err := syscall.Mmap(int(f.Fd()), 0, int(t), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
if err != nil {
    fmt.Println(err)
    os.Exit(1)
}
 // not too sure on reading data on string - doesnt work as expected.
map_array := (*[10000]string)(unsafe.Pointer(&mmap[0]))
map_array[0] = "yellow!"
err = syscall.Munmap(mmap)
if err != nil {
    fmt.Println(err)
    os.Exit(1)
}
newStat, _ := f.Stat()
newSize := newStat.Size()
fmt.Printf("[mmap( ) RW] : size was : %+v\n", newSize)
got = make([]byte, newSize)
if _, err := f.ReadAt(got, 0); err != nil && err != io.EOF {
    panic(err)
}
if len(got) == len(want) {
    fmt.Println("well the lengths are equal atleast??!")
}
if !bytes.Equal(got, want) {
    fmt.Printf("\n [mmap( ) RW] : works! got  %d \n want %d", len(got), len(want))
}

这显然可以按预期工作-但是如果我想通过 mmap() 读取 mmaped 文件上的内容,我该如何从这些字节中读取字符串(我感觉某处可能需要一个编码包也许可以使用,但不安全文档上的 StringHeader 让我感到困惑)。

建议。

【问题讨论】:

  • 可能我不明白你的意思。如果您使用的是mmap,文件的内容是否会以[]byte 的形式提供?要获取字符串,您可以执行 string(mmap[:100]) bytes.Buffer(但可能不是您想要的,因为您避免使用 io.reader/io.writer 模式)
  • 我想避免阅读器 - 但我的问题是我怀疑通过 mmap 将字符串写入字节时,它不会刷新合法字符,只是一些控制字符 - 我怀疑我的编码可能搞砸了 - 有什么建议吗?跨度>
  • 看看https://github.com/riobard/go-mmap。该软件包可用作mmap 用法的参考。要将字符串写入mmap,您可以执行copy(mmap, []byte("Your string"))
  • 我使用 mmap 和 munmap 而不是读、写 I/O 的原因有很多。 如果这些原因与性能有关,那么您是否费心实际进行基准测试mmap()read()/write()?因为如果您出于性能原因像这样使用mmap(),那么您几乎肯定是错的。 Read this answer,尤其是一个 Linus Torvalds 的两个链接,它解释了 mmap() 如何SLOW。请注意,尽管这个答案很好,但作者最后通过比较 mmap()fread() - 缓冲、基于 stdio 和慢速。

标签: file go io system-calls mmap


【解决方案1】:

正如@putu 在评论中指出的那样,可以通过简单的类型转换将字节切片转换为字符串:

asStr = string(byteSlice) // entire slice as a string
partStr = string(byteSlice[:100]) // first 100 bytes as a string

【讨论】:

  • 这不起作用-我正在对从 mmap 获取的字节数组进行不安全的指针转换以获取字符串数组指针-但是当我阅读时我看到一些控制字符可能我没有编码字符串当我通过 mmap 将它们刷新到文件时以正确的方式转换为字节?
  • 控制字符可能在数据中,输出的编码可能与输入的编码不匹配,并且您可能正在对从中间开始的字节片进行字符串转换一个多字节 UTF-8 代码点。
猜你喜欢
  • 2012-03-05
  • 1970-01-01
  • 2020-11-30
  • 2016-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-20
  • 2023-03-18
相关资源
最近更新 更多