零拷貝讀取檔案成 Go 物件
我們觀察到從檔案讀取到 go 物件,需要兩次拷貝:
- 從檔案拷貝到記憶體,成為 [] byte
- 從 [] byte,按照格式進行讀取,拷貝到 go 物件上
怎麼樣優化這個讀取速度呢?
- 利用 mmap,把檔案直接對映到記憶體,go 允許把這片記憶體已經轉化成 [] byte 來使用
- 直接在這個 [] byte 上 “展開” go 物件
所謂” 展開 “就是一個 reinterpret cast,對一個指標的型別重新解讀。
var bytes = []byte{
16, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 0, 0, 0, 0,
'h', 'e', 'l', 'l', 'o'}
假設有這樣一個 [] byte 陣列。這個是直接用 mmap 讀取出來的。
var ptr = &bytes[0]
這個 ptr 就是這片記憶體區域的指標,指向了開頭的第一個元素
type stringHeader struct {
Data uintptr
Len int
}
header := (*stringHeader)(unsafe.Pointer(ptr))
這樣我們就把這個記憶體重新解讀為了一個 stringHeader 了。利用 stringHeader 就可以構造出 string 來。
header.Data = uintptr(unsafe.Pointer(&bytes[16]))
把 stringHeader 的指標指向實際的 hello 資料部分。
str := (*string)(unsafe.Pointer(ptr))
fmt.Println(str) // "hello"
最後再把同一片記憶體區域解讀為 string 型別,就得到了"hello"字串了。整個解碼過程只做了一次 header.Data 的更新,沒有做任何記憶體分配。
相比 Java 來說,go 允許我們使用 go 自己的 heap 外的記憶體。甚至允許把 go 的物件直接在這片記憶體上構造出來。這使得我們的應用可以和檔案系統的快取共享一片記憶體,達到記憶體利用率的最大化。同時相比 protobuf/thrift 來說,gocodec 就是把 cpu 對值的記憶體表示(little endian 的 integer 等),以及 go 語言物件的記憶體表示(stringHeader,sliceHeader)直接拷貝了,減少了編解碼的計算成本。
完整的程式碼,歡迎 star:bloomfilter_test.go
設計了一個編解碼格式叫 github.com/esdb/gocodec
和 protobuf 的對比還沒有測,和 json 相比,毫無懸念地不在一個量級上。
gocodec 200000 10893 ns/op 288 B/op 2 allocs/op json 300 3746169 ns/op 910434 B/op 27 allocs/op
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- IOCP 檔案拷貝
- 物件深拷貝和淺拷貝物件
- go slice深拷貝和淺拷貝Go
- 零拷貝原理
- IO流-檔案拷貝
- 檔案內容拷貝
- 實現物件淺拷貝、深拷貝物件
- 聊聊物件深拷貝和淺拷貝物件
- 物件的深拷貝與淺拷貝物件
- jquery之物件拷貝深拷貝淺拷貝案例講解jQuery物件
- 物件拷貝方式物件
- Java拷貝物件Java物件
- JAVA 物件拷貝Java物件
- go配置檔案讀取Go
- 【JavaScript】物件的淺拷貝與深拷貝JavaScript物件
- PHP 物件導向 - 物件的淺拷貝與深拷貝PHP物件
- Golang命令列拷貝檔案Golang命令列
- Java NIO - 零拷貝Java
- asm拷貝檔案到檔案系統ASM
- 清華尹成帶你實戰GO案例(27)Go 讀取檔案Go
- JavaScript物件的深拷貝以及淺拷貝分析JavaScript物件
- vue物件的拷貝Vue物件
- python 物件拷貝Python物件
- go–讀取檔案的方式Go
- go 讀取.ini配置檔案Go
- [java IO流]之檔案拷貝Java
- c語言拷貝檔案程式C語言
- Python基礎 - 檔案拷貝Python
- 二進位制檔案拷貝
- Java零拷貝一步曲——Linux 中的零拷貝技術JavaLinux
- Asp.net(C#)對檔案操作的方法(讀取,刪除,批量拷貝,刪除...)ASP.NETC#
- vue的深度拷貝物件Vue物件
- JavaScript中物件的拷貝JavaScript物件
- 關於引用物件拷貝物件
- map物件拷貝問題物件
- 三目運算、物件克隆、深拷貝和淺拷貝物件
- 檔案操作(二進位制拷貝)
- 使用expect指令碼SCP拷貝檔案指令碼