• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            Fork me on GitHub
            隨筆 - 215  文章 - 13  trackbacks - 0
            <2017年3月>
            2627281234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678


            專注即時通訊及網(wǎng)游服務(wù)端編程
            ------------------------------------
            Openresty 官方模塊
            Openresty 標(biāo)準(zhǔn)模塊(Opm)
            Openresty 三方模塊
            ------------------------------------
            本博收藏大部分文章為轉(zhuǎn)載,并在文章開頭給出了原文出處,如有再轉(zhuǎn),敬請保留相關(guān)信息,這是大家對原創(chuàng)作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            相冊

            Awesome

            Blog

            Book

            GitHub

            Link

            搜索

            •  

            積分與排名

            • 積分 - 216756
            • 排名 - 118

            最新評論

            閱讀排行榜

            http://blog.csdn.net/vipally/article/details/52940119

            相對于C語言,golang是類型安全的語言。但是安全的代價就是性能的妥協(xié)。 
            下面我們通過Golang中的“黑科技”來一窺Golang不想讓我們看到的“秘密”——string的底層數(shù)據(jù)。 
            通過reflect包,我們可以知道,在Golang底層,string和slice其實都是struct:

            type SliceHeader struct {
                Data uintptr
                Len  int
                Cap  int
            }
            type StringHeader struct {
                Data uintptr
                Len  int
            }
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9

            其中Data是一個指針,指向?qū)嶋H的數(shù)據(jù)地址,Len表示數(shù)據(jù)長度。 
            但是,在string和[]byte轉(zhuǎn)換過程中,Golang究竟悄悄幫我們做了什么,來達到安全的目的? 
            在Golang語言規(guī)范里面,string數(shù)據(jù)是禁止修改的,試圖通過&s[0], &b[0]取得string和slice數(shù)據(jù)指針地址也是不能通過編譯的。 
            下面,我們就通過Golang的“黑科技”來一窺Golang背后的“秘密”。

            //return GoString's buffer slice(enable modify string)
            func StringBytes(s string) Bytes {
                return *(*Bytes)(unsafe.Pointer(&s))
            }
            
            // convert b to string without copy
            func BytesString(b []byte) String {
                return *(*String)(unsafe.Pointer(&b))
            }
            
            // returns &s[0], which is not allowed in go
            func StringPointer(s string) unsafe.Pointer {
                p := (*reflect.StringHeader)(unsafe.Pointer(&s))
                return unsafe.Pointer(p.Data)
            }
            
            // returns &b[0], which is not allowed in go
            func BytesPointer(b []byte) unsafe.Pointer {
                p := (*reflect.SliceHeader)(unsafe.Pointer(&b))
                return unsafe.Pointer(p.Data)
            }
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 11
            • 12
            • 13
            • 14
            • 15
            • 16
            • 17
            • 18
            • 19
            • 20
            • 21
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 11
            • 12
            • 13
            • 14
            • 15
            • 16
            • 17
            • 18
            • 19
            • 20
            • 21

            以上4個函數(shù)的神奇之處在于,通過unsafe.Pointer和reflect.XXXHeader取到了數(shù)據(jù)首地址,并實現(xiàn)了string和[]byte的直接轉(zhuǎn)換(這些操作在語言層面是禁止的)。 
            下面我們就通過這幾個“黑科技”來測試一下語言底層的秘密:

            func TestPointer(t *testing.T) {
                s := []string{
                    "",
                    "",
                    "hello",
                    "hello",
                    fmt.Sprintf(""),
                    fmt.Sprintf(""),
                    fmt.Sprintf("hello"),
                    fmt.Sprintf("hello"),
                }
                fmt.Println("String to bytes:")
                for i, v := range s {
                    b := unsafe.StringBytes(v)
                    b2 := []byte(v)
                    if b.Writeable() {
                        b[0] = 'x'
                    }
                    fmt.Printf("%d\ts=%5s\tptr(v)=%-12v\tptr(StringBytes(v)=%-12v\tptr([]byte(v)=%-12v\n",
                        i, v, unsafe.StringPointer(v), b.Pointer(), unsafe.BytesPointer(b2))
                }
            
                b := [][]byte{
                    []byte{},
                    []byte{'h', 'e', 'l', 'l', 'o'},
                }
                fmt.Println("Bytes to string:")
                for i, v := range b {
                    s1 := unsafe.BytesString(v)
                    s2 := string(v)
                    fmt.Printf("%d\ts=%5s\tptr(v)=%-12v\tptr(StringBytes(v)=%-12v\tptr(string(v)=%-12v\n",
                        i, s1, unsafe.BytesPointer(v), s1.Pointer(), unsafe.StringPointer(s2))
                }
            
            }
            
            const N = 3000000
            
            func Benchmark_Normal(b *testing.B) {
                for i := 1; i < N; i++ {
                    s := fmt.Sprintf("12345678901234567890123456789012345678901234567890")
                    bb := []byte(s)
                    bb[0] = 'x'
                    s = string(bb)
                    s = s
                }
            }
            func Benchmark_Direct(b *testing.B) {
                for i := 1; i < N; i++ {
                    s := fmt.Sprintf("12345678901234567890123456789012345678901234567890")
                    bb := unsafe.StringBytes(s)
                    bb[0] = 'x'
                    s = s
                }
            }
            
            //test result
            //String to bytes:
            //0 s=      ptr(v)=0x51bd70     ptr(StringBytes(v)=0x51bd70     ptr([]byte(v)=0xc042021c58
            //1 s=      ptr(v)=0x51bd70     ptr(StringBytes(v)=0x51bd70     ptr([]byte(v)=0xc042021c58
            //2 s=hello ptr(v)=0x51c2fa     ptr(StringBytes(v)=0x51c2fa     ptr([]byte(v)=0xc042021c58
            //3 s=hello ptr(v)=0x51c2fa     ptr(StringBytes(v)=0x51c2fa     ptr([]byte(v)=0xc042021c58
            //4 s=      ptr(v)=<nil>        ptr(StringBytes(v)=<nil>        ptr([]byte(v)=0xc042021c58
            //5 s=      ptr(v)=<nil>        ptr(StringBytes(v)=<nil>        ptr([]byte(v)=0xc042021c58
            //6 s=xello ptr(v)=0xc0420444b5 ptr(StringBytes(v)=0xc0420444b5 ptr([]byte(v)=0xc042021c58
            //7 s=xello ptr(v)=0xc0420444ba ptr(StringBytes(v)=0xc0420444ba ptr([]byte(v)=0xc042021c58
            //Bytes to string:
            //0 s=      ptr(v)=0x5c38b8     ptr(StringBytes(v)=0x5c38b8     ptr(string(v)=<nil>
            //1 s=hello ptr(v)=0xc0420445e0 ptr(StringBytes(v)=0xc0420445e0 ptr(string(v)=0xc042021c38
            //Benchmark_Normal-4    1000000000           0.87 ns/op
            //Benchmark_Direct-4    2000000000           0.24 ns/op
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 11
            • 12
            • 13
            • 14
            • 15
            • 16
            • 17
            • 18
            • 19
            • 20
            • 21
            • 22
            • 23
            • 24
            • 25
            • 26
            • 27
            • 28
            • 29
            • 30
            • 31
            • 32
            • 33
            • 34
            • 35
            • 36
            • 37
            • 38
            • 39
            • 40
            • 41
            • 42
            • 43
            • 44
            • 45
            • 46
            • 47
            • 48
            • 49
            • 50
            • 51
            • 52
            • 53
            • 54
            • 55
            • 56
            • 57
            • 58
            • 59
            • 60
            • 61
            • 62
            • 63
            • 64
            • 65
            • 66
            • 67
            • 68
            • 69
            • 70
            • 71
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 11
            • 12
            • 13
            • 14
            • 15
            • 16
            • 17
            • 18
            • 19
            • 20
            • 21
            • 22
            • 23
            • 24
            • 25
            • 26
            • 27
            • 28
            • 29
            • 30
            • 31
            • 32
            • 33
            • 34
            • 35
            • 36
            • 37
            • 38
            • 39
            • 40
            • 41
            • 42
            • 43
            • 44
            • 45
            • 46
            • 47
            • 48
            • 49
            • 50
            • 51
            • 52
            • 53
            • 54
            • 55
            • 56
            • 57
            • 58
            • 59
            • 60
            • 61
            • 62
            • 63
            • 64
            • 65
            • 66
            • 67
            • 68
            • 69
            • 70
            • 71

            結(jié)論如下: 
            1.string常量會在編譯期分配到只讀段,對應(yīng)數(shù)據(jù)地址不可寫入,并且相同的string常量不會重復(fù)存儲。 
            2.fmt.Sprintf生成的字符串分配在堆上,對應(yīng)數(shù)據(jù)地址可修改。 
            3.常量空字符串有數(shù)據(jù)地址,動態(tài)生成的字符串沒有設(shè)置數(shù)據(jù)地址 
            4.Golang string和[]byte轉(zhuǎn)換,會將數(shù)據(jù)復(fù)制到堆上,返回數(shù)據(jù)指向復(fù)制的數(shù)據(jù) 
            5.動態(tài)生成的字符串,即使內(nèi)容一樣,數(shù)據(jù)也是在不同的空間 
            6.只有動態(tài)生成的string,數(shù)據(jù)可以被黑科技修改 
            8.string和[]byte通過復(fù)制轉(zhuǎn)換,性能損失接近4倍

            我將測試代碼放在這里,歡迎參考: 
            https://github.com/vipally/gx/blob/master/unsafe/string_test.go

            參考資料: 
            [1] Go語言黑魔法 http://studygolang.com/articles/2909

            posted on 2017-05-04 10:32 思月行云 閱讀(580) 評論(0)  編輯 收藏 引用 所屬分類: Golang
            国产精品久久久久蜜芽| 99久久国产主播综合精品| 久久性生大片免费观看性| 国内精品免费久久影院| 久久久精品视频免费观看| 97久久婷婷五月综合色d啪蜜芽| 天天爽天天狠久久久综合麻豆| 国产精品久久国产精品99盘 | 狠狠精品干练久久久无码中文字幕 | 久久夜色精品国产www| 国产精品久久久香蕉| 久久96国产精品久久久| 亚洲欧美成人久久综合中文网| 欧美黑人又粗又大久久久| 久久99精品国产99久久6| 亚洲午夜无码久久久久| 久久99精品久久久久久秒播| 亚洲乱码中文字幕久久孕妇黑人| 人人狠狠综合久久亚洲88| 伊人久久成人成综合网222| 国产精品免费久久久久久久久 | 精品久久久久久久久久中文字幕| 国产呻吟久久久久久久92| 99热都是精品久久久久久| 无码AV中文字幕久久专区| 久久伊人影视| 久久久久九国产精品| 99久久无码一区人妻| 国产午夜福利精品久久2021| 中文精品久久久久人妻不卡| 欧美久久一级内射wwwwww.| 国产综合精品久久亚洲| 99热精品久久只有精品| 9191精品国产免费久久| 久久久久久综合一区中文字幕| 久久婷婷国产综合精品| 亚洲国产另类久久久精品| 久久乐国产综合亚洲精品| 麻豆久久久9性大片| 久久久久久综合网天天| 久久亚洲精品无码VA大香大香|