最近寫程序過程感受golang讀寫文件比較慢。所以決定讀一下源碼。golang
src/os/file.gowindows
http://www.ieyebrain.com:8080/golang/src/os/file.goapp
中定義了file的函數:less
Name, Read,Write,Seek,Close等等。函數
例如:Read函數ui
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中,接口
http://www.ieyebrain.com:8080/golang/src/os/file_windows.goget
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/pwriteinput
// 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 http://www.ieyebrain.com:8080/golang/src/syscall/syscall_windows.go
func Read(fd Handle, p []byte) (n int, err error) -> ReadFile
2 http://www.ieyebrain.com:8080/golang/src/syscall/zsyscall_windows.go
func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
3 http://www.ieyebrain.com:8080/golang/src/runtime/syscall_windows.go
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 }