假设文件Foo.txt的内容如下所示。
Foo Bar Bar Foo请考虑下面的简短程序。
package main
import "syscall"
import "fmt"
func main() {
fd, err := syscall.Open("Foo.txt", syscall.O_RDONLY, 0)
if err != nil {
fmt.Println("Failed on open: ", err)
}
data := make([]byte, 100)
_, err = syscall.Read(fd, data)
if err != nil {
fmt.Println("Failed on read: ", err)
}
syscall.Close(fd)
}当我们运行上面的程序,我们没有错误,这是正确的行为。
现在,我修改syscall.Open行如下。
fd, err := syscall.Open("Foo.txt", syscall.O_RDONLY | syscall.O_SYNC | syscall.O_DIRECT, 0)当我再次运行程序时,我会得到以下(不受欢迎的)输出。
Failed on read: invalid argumentsyscall.O_SYNC如何正确传递由 手册页 为跳过文件系统缓存而指定的标志、、和?
请注意,我直接使用syscall文件接口而不是os文件接口,因为我无法找到将这些标志传递到os提供的函数的方法,但我对使用os的解决方案开放,只要它们在读取时正确地禁用文件系统缓存。
还请注意,我正在Ubuntu 14.04上运行,ext4是我的文件系统。
Update:我尝试在下面的代码中使用@Nick的包。
package main
import "io"
import "github.com/ncw/directio"
import "os"
import "fmt"
func main() {
in, err := directio.OpenFile("Foo.txt", os.O_RDONLY, 0666)
if err != nil {
fmt.Println("Error on open: ", err)
}
block := directio.AlignedBlock(directio.BlockSize)
_, err = io.ReadFull(in, block)
if err != nil {
fmt.Println("Error on read: ", err)
}
}输出如下
Error on read: unexpected EOF发布于 2015-10-13 15:05:46
你可以享受我为这个目的而制作的定向包。
从现场
这是Go语言的库,可以在所有支持的Go OSes ( openbsd和plan9除外)下使用Direct。
直接IO在不缓冲操作系统数据的情况下对磁盘执行IO操作。当您正在读取或写入大量不希望填充OS缓存的数据时,它非常有用。
请参阅这里的包文档
http://go.pkgdoc.org/github.com/ncw/directio
发布于 2015-10-13 11:09:41
来自open手册页面,在说明下面:
O_DIRECT标志可以对用户空间缓冲区的长度和地址以及I/O的文件偏移量施加对齐限制。在Linux中,对齐的限制因文件系统和内核版本而异,可能完全不存在。
因此,您可能会出现内存或文件偏移量的对齐问题,或者您的缓冲区大小可能“错误”。什么路线和大小应该是不明显的。该手册页继续写道:
但是,应用程序目前没有独立于文件系统的接口来发现给定文件或文件系统的这些限制。
甚至连莱纳斯也以他一贯轻描淡写的方式来衡量:
“O_DIRECT一直困扰我的是,整个界面都很愚蠢,很可能是由一只精神错乱的猴子设计的,有一些严重的精神控制物质。”-Linus。
祝好运!
附注:暗处刺痛:为什么不读取512字节?
发布于 2016-08-13 07:23:50
你可以尝试使用建议和建议,但没有保证。这两种方法都可能对较大的文件/数据起作用,因为:
部分页被故意保留是因为期望保留所需的内存比丢弃不需要的内存要好。
看一下linux源代码,什么能做什么不做什么。例如,POSIX_FADV_NOREUSE什么也不做。
http://lxr.free-electrons.com/source/mm/fadvise.c#L62
http://lxr.free-electrons.com/source/mm/madvise.c
package main
import "fmt"
import "os"
import "syscall"
import "golang.org/x/sys/unix"
func main() {
advise := false
if len(os.Args) > 1 && os.Args[1] == "-x" {
fmt.Println("setting file advise")
advise =true
}
data := make([]byte, 100)
handler, err := os.Open("Foo.txt")
if err != nil {
fmt.Println("Failed on open: ", err)
}; defer handler.Close()
if advise {
unix.Fadvise(int(handler.Fd()), 0, 0, 4) // 4 == POSIX_FADV_DONTNEED
}
read, err := handler.Read(data)
if err != nil {
fmt.Println("Failed on read: ", err)
os.Exit(1)
}
if advise {
syscall.Madvise(data, 4) // 4 == MADV_DONTNEED
}
fmt.Printf("read %v bytes\n", read)
}/usr/bin/time -v ./ -x
Command being timed: "./direct -x"
User time (seconds): 0.00
System time (seconds): 0.00
Percent of CPU this job got: 0%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 1832
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 2
Minor (reclaiming a frame) page faults: 149
Voluntary context switches: 2
Involuntary context switches: 2
Swaps: 0
File system inputs: 200
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0https://stackoverflow.com/questions/33095053
复制相似问题