golang []byte和string的高性能轉換


golang []byte和string的高性能轉換

fasthttp的最佳實踐中有這么一句話:

Avoid conversion between []byte and string, since this may result in memory allocation+copy. Fasthttp API provides functions for both []byte and string - use these functions instead of converting manually between []byte and string. There are some exceptions - see this wiki page for more details.

大概意思就是說,要盡量避免[]bytestring的轉換,因為轉換過程會存在內存拷貝,影響性能。此外在fasthttp中還提出了一個解決方案,用於[]bytestring的高性能轉換。直接看下源碼:

// b2s converts byte slice to a string without memory allocation.
// See https://groups.google.com/forum/#!msg/Golang-Nuts/ENgbUzYvCuU/90yGx7GUAgAJ .
//
// Note it may break if string and/or slice header will change
// in the future go versions.
func b2s(b []byte) string {
	/* #nosec G103 */
	return *(*string)(unsafe.Pointer(&b))
}

// s2b converts string to a byte slice without memory allocation.
//
// Note it may break if string and/or slice header will change
// in the future go versions.
func s2b(s string) (b []byte) {
	/* #nosec G103 */
	bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	/* #nosec G103 */
	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
	bh.Data = sh.Data
	bh.Cap = sh.Len
	bh.Len = sh.Len
	return b
}

可以看到上述實現中並沒有內存拷貝,使用類似C語言的類型強轉實現[]bytestring之間的類型轉換。那么他們和一般使用的轉換之間的性能差異有多大?看下如下性能測試:

var s = "adsfasdfadsfadsfasdfadfadfasdfasdfadsfasdfasdfasdfsadfas"
func BenchmarkB2sFast(b *testing.B) {
    for i := 0; i < b.N; i++ {
       _ = s2b(s)
    }
}

func BenchmarkB2sStd(b *testing.B) {
    var _ []byte
    for i := 0; i < b.N; i++ {
        _ = []byte(s)
    }
}

var bt = []byte("adsfasdfadsfadsfasdfadfadfasdfasdfadsfasdfasdfasdfsadfas")
func BenchmarkS2BFast(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _ = b2s(bt)
    }
}

func BenchmarkS2BStd(b *testing.B) {
    var _ []byte
    for i := 0; i < b.N; i++ {
        _ = string(bt)
    }
}

測試結果如下:

goos: windows
goarch: amd64
pkg: awesomeProject5/lib
cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz
BenchmarkB2sFast
BenchmarkB2sFast-8   	1000000000	         0.2383 ns/op
BenchmarkB2sStd
BenchmarkB2sStd-8    	41089557	        27.65 ns/op
BenchmarkS2BFast
BenchmarkS2BFast-8   	1000000000	         0.2378 ns/op
BenchmarkS2BStd
BenchmarkS2BStd-8    	54249056	        22.51 ns/op
PASS

可以看到在相同測試條件下,其性能差異竟然達到了100倍!

可見在高頻網絡訪問中,如果直接在[]bytestring之間進行轉換將會花費多大的性能!

需要注意的是這種方式也有弊端,在代碼注釋中可以看到它依賴golang中的string或slice的首部定義。如果后續golang版本對此有修改,則有可能導致代碼無法運行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM