青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Fork me on GitHub
隨筆 - 215  文章 - 13  trackbacks - 0
<2016年11月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910


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

常用鏈接

留言簿(1)

隨筆分類(lèi)

隨筆檔案

相冊(cè)

Awesome

Blog

Book

GitHub

Link

搜索

  •  

積分與排名

  • 積分 - 221316
  • 排名 - 117

最新評(píng)論

閱讀排行榜

作者:達(dá)達(dá)
鏈接:https://zhuanlan.zhihu.com/p/20010926
來(lái)源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

今天我要教大家一些無(wú)用技能,也可以叫它奇技淫巧或者黑魔法。用得好可以提升性能,用得不好就會(huì)招來(lái)惡魔,嘿嘿。

黑魔法導(dǎo)論

為了讓大家在學(xué)習(xí)了基礎(chǔ)黑魔法之后能有所悟,在必要的時(shí)候能創(chuàng)造出本文傳授之外的屬于自己的魔法,這里需要先給大家打好基礎(chǔ)。

學(xué)習(xí)Go語(yǔ)言黑魔法之前,需要先看清Go世界的本質(zhì),你才能獲得像Neo一樣的能力。

在Go語(yǔ)言中,Slice本質(zhì)是什么呢?是一個(gè)reflect.SliceHeader結(jié)構(gòu)體和這個(gè)結(jié)構(gòu)體中Data字段所指向的內(nèi)存。String本質(zhì)是什么呢?是一個(gè)reflect.StringHeader結(jié)構(gòu)體和這個(gè)結(jié)構(gòu)體所指向的內(nèi)存。

在Go語(yǔ)言中,指針的本質(zhì)是什么呢?是unsafe.Pointer和uintptr。

當(dāng)你清楚了它們的本質(zhì)之后,你就可以隨意的玩弄它們,嘿嘿嘿。

第一式 - 獲得Slice和String的內(nèi)存數(shù)據(jù)

讓我小試身手,你有一個(gè)CGO接口要調(diào)用,需要你把一個(gè)字符串?dāng)?shù)據(jù)或者字節(jié)數(shù)組數(shù)據(jù)從Go這邊傳遞到C那邊,比如像這個(gè):mysql/conn.go at master · funny/mysql · GitHub

查了各種教程和文檔,它們都告訴你要用C.GoString或C.GoBytes來(lái)轉(zhuǎn)換數(shù)據(jù)。

但是,當(dāng)你調(diào)用這兩個(gè)函數(shù)的時(shí)候,發(fā)生了什么事情呢?這時(shí)候Go復(fù)制了一份數(shù)據(jù),然后再把新數(shù)據(jù)的地址傳給C,因?yàn)镚o不想冒任何風(fēng)險(xiǎn)。

你的C程序只是想一次性的用一下這些數(shù)據(jù),也不得不做一次數(shù)據(jù)復(fù)制,這對(duì)于一個(gè)性能癖來(lái)說(shuō)是多麼可怕的一個(gè)事實(shí)!

這時(shí)候我們就需要一個(gè)黑魔法,來(lái)做到不拷貝數(shù)據(jù)又能把指針地址傳遞給C。

// 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 bytePointer(b []byte) unsafe.Pointer {
	p := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	return unsafe.Pointer(p.Data)
}

以上就是黑魔法第一式,我們先去到Go字符串的指針,它本質(zhì)上是一個(gè)*reflect.StringHeader,但是Go告訴我們這是一個(gè)*string,我們告訴Go它同時(shí)也是一個(gè)unsafe.Pointer,Go說(shuō)好吧它是,于是你得到了unsafe.Pointer,接著你就躲過(guò)了Go的監(jiān)視,偷偷的把unsafe.Pointer轉(zhuǎn)成了*reflect.StringHeader。

有了*reflect.StringHeader,你很快就取到了Data字段指向的內(nèi)存地址,它就是Go保護(hù)著不想給你看到的隱秘所在,你把這個(gè)地址偷偷告訴給了C,于是C就愉快的偷看了Go的隱私。

第二式 - 把[]byte轉(zhuǎn)成string

你肯定要笑,要把[]byte轉(zhuǎn)成string還不簡(jiǎn)單?Go語(yǔ)言初學(xué)者都會(huì)的類(lèi)型轉(zhuǎn)換語(yǔ)法:string(b)。

但是你知道這么做的代價(jià)嗎?既然我們能隨意的玩弄SliceHeader和StringHeader,為什么我們不能造個(gè)string給Go呢?Go的內(nèi)部會(huì)不會(huì)就是這么做的呢?

先上個(gè)實(shí)驗(yàn)吧:

package labs28

import "testing"
import "unsafe"

func Test_ByteString(t *testing.T) {
	var x = []byte("Hello World!")
	var y = *(*string)(unsafe.Pointer(&x))
	var z = string(x)

	if y != z {
		t.Fail()
	}
}

func Benchmark_Normal(b *testing.B) {
	var x = []byte("Hello World!")
	for i := 0; i < b.N; i ++ {
		_ = string(x)
	}
}

func Benchmark_ByteString(b *testing.B) {
	var x = []byte("Hello World!")
	for i := 0; i < b.N; i ++ {
		_ = *(*string)(unsafe.Pointer(&x))
	}
}

這個(gè)實(shí)驗(yàn)先證明了我們可以用[]byte的數(shù)據(jù)造個(gè)string給Go。接著做了兩組Benchmark,分別測(cè)試了普通的類(lèi)型轉(zhuǎn)換和偽造string的效率。

結(jié)果如下:

$ go test -bench="."
PASS
Benchmark_Normal    20000000            63.4 ns/op
Benchmark_ByteString    2000000000           0.55 ns/op
ok      github.com/idada/go-labs/labs28 2.486s

喲西,顯然Go這次又為了穩(wěn)定性做了些復(fù)制數(shù)據(jù)之類(lèi)的事情了!這讓性能癖怎么能忍受!

我現(xiàn)在手頭有個(gè)[]byte,但是我想用strconv.Atoi()把它轉(zhuǎn)成字面含義對(duì)應(yīng)的整數(shù)值,竟然需要發(fā)生一次數(shù)據(jù)拷貝把它轉(zhuǎn)成string,比如像這樣:mysql/types.go at master · funny/mysql · GitHub,這實(shí)在不能忍啊!

出招:

// convert b to string without copy
func byteString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

我們?nèi)〉絒]byte的指針,這次Go又告訴你它是*byte不是*string,你告訴它滾犢子這是unsafe.Pointer,Go這下又老實(shí)了,接著你很自在的把*byte轉(zhuǎn)成了*string,因?yàn)槟阒纑eflect.StringHeader和reflect.SliceHeader的結(jié)構(gòu)體只相差末尾一個(gè)字段,兩者的內(nèi)存是對(duì)齊的,沒(méi)必要再取Data字段了,直接轉(zhuǎn)吧。

于是,世界終于安寧了,嘿嘿。

第三式 - 結(jié)構(gòu)體和[]byte互轉(zhuǎn)

有一天,你想把一個(gè)簡(jiǎn)單的結(jié)構(gòu)體轉(zhuǎn)成二進(jìn)制數(shù)據(jù)保存起來(lái),這時(shí)候你想到了encoding/gob和encoding/json,做了一下性能測(cè)試,你想到效率有沒(méi)有可能更高點(diǎn)?

于是你又試了encoding/binady,性能也還可以,但是你還不滿意。但是瓶頸在哪里呢?你恍然大悟,最高效的辦法就是完全不解析數(shù)據(jù)也不產(chǎn)生數(shù)據(jù)啊!

怎么做?是時(shí)候使用這個(gè)黑魔法了:

type MyStruct struct {
	A int
	B int
}

var sizeOfMyStruct = int(unsafe.Sizeof(MyStruct{}))

func MyStructToBytes(s *MyStruct) []byte {
	var x reflect.SliceHeader
	x.Len = sizeOfMyStruct
	x.Cap = sizeOfMyStruct
	x.Data = uintptr(unsafe.Pointer(s))
	return *(*[]byte)(unsafe.Pointer(&x))
}

func BytesToMyStruct(b []byte) *MyStruct {
	return (*MyStruct)(unsafe.Pointer(
		(*reflect.SliceHeader)(unsafe.Pointer(&b)).Data,
	))
}

這是個(gè)曲折但又熟悉的故事。你造了一個(gè)SliceHeader,想把它的Data字段指向你的結(jié)構(gòu)體,但是Go又告訴你不可以,你像往常那樣把Go提到一邊,你得到了unsafe.Pointer,但是這次Go有不死心,它告訴你Data是uintptr,unsafe.Pointer不是uintptr,你大腳把它踢開(kāi),怒吼道:unsafe.Pointer就是uintptr,你少拿這些概念糊弄我,Go屁顛屁顛的跑開(kāi)了,現(xiàn)在你一馬平川的來(lái)到了函數(shù)的出口,Go竟然已經(jīng)在哪里等著你了!你上前三下五除二把它踢得遠(yuǎn)遠(yuǎn)的,順利的把手頭的SliceHeader轉(zhuǎn)成了[]byte。

過(guò)了一陣子,你拿到了一個(gè)[]byte,你知道需要把它轉(zhuǎn)成MyStruct來(lái)讀取其中的數(shù)據(jù)。Go這時(shí)候已經(jīng)完全不是你的對(duì)手了,它已經(jīng)洗好屁股在函數(shù)入口等你,你一行代碼就解決了它。

第四式 - 用CGO優(yōu)化GC

你已經(jīng)是Go世界的Neo,Go跟本沒(méi)辦法拿你怎么樣。但是有一天Go的GC突然抽風(fēng)了,原來(lái)這貨是不管對(duì)象怎么用的,每次GC都給來(lái)一遍人口普查,導(dǎo)致系統(tǒng)暫停時(shí)間很長(zhǎng)。

可是你是個(gè)性能癖,你把一堆數(shù)據(jù)都放在內(nèi)存里方便快速訪問(wèn),你這時(shí)候很想再踢Go的屁股,但是你沒(méi)辦法,畢竟你還在Go的世界里,你現(xiàn)在得替它擦屁股了,你似乎看到Go躲在一旁偷笑。

你想到你手頭有CGO,可以輕易的用C申請(qǐng)到Go世界外的內(nèi)存,Go的GC不會(huì)掃描這部分內(nèi)存。

你還想到你可以用unsafe.Pointer將C的指針轉(zhuǎn)成Go的結(jié)構(gòu)體指針。于是一大批常駐內(nèi)存對(duì)象被你用這種方式轉(zhuǎn)成了Go世界的黑戶,Go的GC一下子輕松了下來(lái)。

但是你手頭還有很多Slice,于是你就利用C申請(qǐng)內(nèi)存給SliceHeader來(lái)構(gòu)造自己的Slice,于是你旗下的Slice紛紛轉(zhuǎn)成了Go世界的黑戶,Go的GC終于平靜了。

但好景總是不長(zhǎng)久,有一天Go世界突然崩潰了,只留下一句話:Segmentation Fault。你一下慫了,怎么段錯(cuò)誤了?

經(jīng)過(guò)一個(gè)通宵排查,你發(fā)現(xiàn)你管轄的黑戶對(duì)象竟然偷偷的跟Go世界的其它合法居民搞在一起,當(dāng)Go世界以為某個(gè)居民已經(jīng)消亡時(shí),用GC回收了它的住所,但是你的地下世界卻認(rèn)為它還活著,還繼續(xù)訪問(wèn)它。

于是你廢了一番功夫斬?cái)嗔怂嘘P(guān)聯(lián),世界暫時(shí)寧?kù)o了下來(lái)。

但是你已經(jīng)很累了,這時(shí)候你想起一句話:

為無(wú)為,則無(wú)不治
posted on 2017-05-04 10:35 思月行云 閱讀(183) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): Golang
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            日韩视频免费观看| 亚洲电影在线观看| 国产美女一区二区| 久久久五月婷婷| 99精品99| 欧美freesex交免费视频| 一区二区三区av| 一区在线视频观看| 国产精品豆花视频| 免费成人av资源网| 久久精品99国产精品酒店日本| 亚洲国产精品一区二区尤物区 | 亚洲国产高潮在线观看| 欧美日韩在线视频观看| 欧美激情久久久| 久久久久国产精品人| 一本久久综合亚洲鲁鲁| 亚洲人线精品午夜| 免费看精品久久片| 久久在线视频| 久久手机免费观看| 久久久999精品免费| 亚洲欧美一区二区三区久久| 日韩一级黄色片| 亚洲九九爱视频| 日韩视频免费看| 国产精品久久久久久久久免费| 免费视频一区| 开心色5月久久精品| 欧美影院成人| 久久久精品动漫| 麻豆9191精品国产| 亚洲国产天堂久久国产91| 亚洲精品小视频在线观看| 亚洲黑丝在线| 亚洲一区激情| 巨胸喷奶水www久久久免费动漫| 久久精品国产综合精品| 久久国产精品久久久久久久久久 | 国产在线播放一区二区三区| 国产精品久久久久久亚洲调教 | 国产精品久久久久影院亚瑟| 欧美午夜欧美| 国产一区二区三区久久久| 亚洲激情午夜| 午夜精品久久久久影视 | 六月丁香综合| 中文欧美字幕免费| 久久激情综合网| 欧美人交a欧美精品| 国产精品一区二区久激情瑜伽| 伊人色综合久久天天| 亚洲最新在线视频| 农村妇女精品| 亚洲一区二区三区国产| 欧美福利视频一区| 在线电影国产精品| 久久久久久久综合狠狠综合| 亚洲精品在线二区| 欧美成年人视频网站欧美| 韩国一区电影| 久久九九热免费视频| 亚洲天堂免费在线观看视频| 欧美理论电影在线播放| 亚洲狠狠丁香婷婷综合久久久| 亚洲午夜精品网| 亚洲免费大片| 欧美日韩午夜在线| 亚洲综合大片69999| 99在线热播精品免费| 久久色中文字幕| 久久gogo国模裸体人体| 一区二区三区在线观看欧美 | 欧美专区第一页| 欧美日韩久久久久久| 一本色道久久综合亚洲精品不卡| 亚洲第一在线综合网站| 毛片一区二区| 99视频精品免费观看| a91a精品视频在线观看| 国产精品区二区三区日本 | 性欧美激情精品| 欧美在线视频观看| 在线视频精品| 久久成人av少妇免费| 亚洲国产精品小视频| 欧美一区二区性| 亚洲精品久久久久| 久久久久久久久久久久久女国产乱| 伊人影院久久| 日韩一区二区精品葵司在线| 国产精品一区二区在线观看不卡 | 国产一区免费视频| 亚洲国产成人在线视频| 国产视频不卡| 一区二区三区视频在线看| 永久久久久久| 亚洲欧美日韩国产成人| 亚洲第一免费播放区| 最新日韩av| 影音欧美亚洲| 久久精品官网| 欧美一区二区| 国产精品va| av成人国产| 亚洲影院污污.| 欧美二区视频| 欧美不卡高清| 亚洲高清不卡在线观看| 久久99伊人| 另类av一区二区| 韩国一区二区三区在线观看| 欧美在线观看一区| 久久久久久伊人| 欧美午夜不卡在线观看免费 | 亚洲自拍都市欧美小说| 欧美视频亚洲视频| 亚洲午夜精品| 欧美成人综合一区| 国产手机视频一区二区| 蜜月aⅴ免费一区二区三区| 午夜一区不卡| 欧美综合国产| 麻豆成人在线播放| 亚洲午夜激情网站| 亚洲精品网址在线观看| 午夜国产精品影院在线观看| 欧美日韩国产不卡在线看| 亚洲自拍高清| 亚洲国产美女久久久久 | 亚洲欧美bt| 亚洲伦理久久| 亚洲国产精品福利| 另类国产ts人妖高潮视频| 欧美中文字幕视频| 亚洲综合色丁香婷婷六月图片| 亚洲精品久久久久久久久久久久| 激情自拍一区| 国产一区二区三区在线观看精品| 国产精品美女xx| 国产精品久久久久毛片软件| 欧美调教视频| 欧美午夜精品理论片a级大开眼界 欧美午夜精品理论片a级按摩 | 亚洲精品少妇网址| 亚洲女同精品视频| 女女同性精品视频| 一本色道久久88综合亚洲精品ⅰ | 久久久99爱| 亚洲国产裸拍裸体视频在线观看乱了 | 欧美高清视频一区| 一本色道久久综合亚洲精品小说| 欧美成人精品| 亚洲精品久久视频| 欧美一区二区三区喷汁尤物| 激情久久五月| 欧美日韩一区国产| 久久精品国产欧美亚洲人人爽| 久久综合久久久久88| 亚洲伦理久久| 国产亚洲精品7777| 欧美激情精品久久久久久变态| 一本色道久久综合狠狠躁篇怎么玩| 性欧美xxxx视频在线观看| 亚洲精品久久久久久久久久久久久| 欧美激情网友自拍| 久久9热精品视频| 性8sex亚洲区入口| 亚洲一区二区日本| 欧美承认网站| 亚洲精品视频免费在线观看| 欧美日韩视频一区二区三区| 亚洲影院色在线观看免费| 最新日韩在线| 亚洲一区二区黄色| 亚洲毛片av在线| 老妇喷水一区二区三区| 欧美一区二区啪啪| 亚洲欧美国产高清| 亚洲香蕉视频| 久久精品国产久精国产思思| 久久夜色精品国产噜噜av| 亚洲激情自拍| 亚洲欧美国产不卡| 欧美大片免费观看在线观看网站推荐| 欧美巨乳在线| 国产性猛交xxxx免费看久久| 亚洲精品乱码久久久久久黑人 | 久久综合九色综合欧美就去吻 | 国产精品99久久久久久有的能看| 国产视频欧美| 国产在线日韩| 亚洲福利在线视频| 香蕉成人久久| 久久综合激情| 夜夜夜精品看看| 中文一区二区| 欧美aaaaaaaa牛牛影院| 精品不卡视频| 欧美激情精品久久久久久大尺度| 老司机免费视频一区二区三区|