最近写程序过程感觉golang读写文件比较慢。因此决定读一下源码。
src/os/file.go
中定义了file的函数:
Name, Read,Write,Seek,Close等等。
例如:Read函数
func (f *File) Read(b []byte) (n int, err error) {
if f == nil { return 0, ErrInvalid } n, e := f.read(b) if n == 0 && len(b) > 0 && e == nil { return 0, io.EOF } if e != nil { err = &PathError{"read", f.name, e} } return n, err }这里实现了委托调用的接口技巧。就是把Read操作委托给f.read函数。f为File类型指针,找了一圈,才发现它定义在具体实现的文件中。比如:file_windows.go中,
type File struct {
*file } type file struct { fd syscall.Handle name string dirinfo *dirInfo // nil unless directory being read l sync.Mutex // used to implement windows pread/pwrite// only for console io
isConsole bool lastbits []byte // first few bytes of the last incomplete rune in last write readbuf []rune // input console buffer }下面是读取的正主,syscall.Read(f.fd,b)。 File -> file -> syscall -> WindowsAPI
多了三次调用,File -> file是实现跨平台。 file 这一层加了一个锁。这个可能是一个大的消耗。这个锁是为了统一的操作语义,在Unix平台上,并没有这个锁。
func (f *File) read(b []byte) (n int, err error) {
f.l.Lock() defer f.l.Unlock() if f.isConsole { return f.readConsole(b) } return fixCount(syscall.Read(f.fd, b)) }调用过程:
1
func Read(fd Handle, p []byte) (n int, err error) -> ReadFile
2
func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
3
func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
c := &getg().m.syscall c.fn = fn c.n = nargs c.args = uintptr(noescape(unsafe.Pointer(&a1))) cgocall(asmstdcallAddr, unsafe.Pointer(c)) return c.r1, c.r2, c.err }