<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go中的一些優(yōu)化筆記,簡約而不簡單

          共 3180字,需瀏覽 7分鐘

           ·

          2022-07-17 17:30

          今天小土給大家?guī)硪黄P(guān)于 Golang 項目中最簡單的優(yōu)化的文章。原文見 Golang: simple optimization notes[1]

          我們這里簡單聊一下優(yōu)化本身,然后我們直接從實際的示例開始。

          為什么要優(yōu)化呢?

          當(dāng)你資源占有較高的話會需要很大的成本,雖然現(xiàn)在服務(wù)器資源也不是很貴,但是你還是需要針對的做一些優(yōu)化工作。

          另外每個優(yōu)化應(yīng)該建立在一個benchmark的基礎(chǔ)上,需要體現(xiàn)它給我們帶來多大的收益。

          下面主要從slice、string、struct、function、map、interface、channel、pointer等方面羅列了一些常見的優(yōu)化點。

          數(shù)組和slice優(yōu)化篇

          提前為slice分配內(nèi)存

          盡量使用第三個參數(shù): make([]T, 0, len)

          如果你事先不知道確切的數(shù)量并且slice是臨時的,你可以設(shè)置得大一些,只要slice在運行時不會增長。

          不要忘記使用“copy”

          我們盡量不要在復(fù)制時使用 append,例如,在合并兩個或多個slice時。

          正確地使用迭代

          如果我們有一個包含很多元素或比較大的元素的slice,我們會嘗試使用“for”或 range 單個元素。通過這種方法,可以避免不必要的復(fù)制。

          學(xué)會復(fù)用slice

          如果我們需要對傳入的slice進行某種操作并返回結(jié)果,我們可以直接return,但已經(jīng)修改了。這樣我們就可以避免了新的內(nèi)存分配。

          不要留下未使用的slice

          如果我們需要從slice中切下一小塊并僅使用它,其實主要部分也會保留下來。可以使用copy產(chǎn)生一個新的slice,而舊的對象讓GC回收。

          string-字符串優(yōu)化篇

          正確地進行拼接

          如果拼接字符串可以在一個語句中完成,那么可以使用“+”,如果需要在循環(huán)中執(zhí)行此操作,那么可以使用string.Builder。通過“Grow”也可以預(yù)先指定builder的大小。

          使用轉(zhuǎn)換優(yōu)化

          由于字符串是由字節(jié)組成的,因此有時這兩種類型之間的轉(zhuǎn)換可以避免內(nèi)存分配。

          使用池化技術(shù)

          我們可以池化字符串,從而幫助編譯器只存儲一次相同的字符串。

          避免內(nèi)存分配

          我們可以使用map來替代復(fù)合鍵,我們也可以使用[]byte。盡量不要使用fmt包,因為它的所有函數(shù)都使用了反射。

          struct-結(jié)構(gòu)體優(yōu)化篇

          避免復(fù)制大的struct

          我們理解的小struct,是指不超過 4 個字段的struct,不超過一個機器字

          標準的copy案例

          • 轉(zhuǎn)換成interface
          • 接收和發(fā)送到channel
          • 替換map中的item
          • 向slice添加元素
          • 迭代(range)

          避免通過指針來訪問struct中的字段

          解引用是比較昂貴的,我們可以盡量少做,尤其是在循環(huán)中。我們也會失去使用快速寄存器的能力。

          使用小型的struct

          這項工作由編譯器優(yōu)化的,這意味著它的工作量很小。

          通過內(nèi)存對齊來減小struct大小

          我們可以對齊struct(根據(jù)字段的大小,以正確的順序排列),從而可以減小struct本身的大小。

          func-函數(shù)優(yōu)化篇

          使用內(nèi)聯(lián)函數(shù)或自己內(nèi)聯(lián)

          我們盡量編寫一些可供編譯器內(nèi)聯(lián)的小函數(shù)——它很快,但自己從函數(shù)中嵌入代碼則更快。對于熱路徑函數(shù)尤其如此。

          什么情況下不會被內(nèi)聯(lián)?

          • recovery 函數(shù)
          • select
          • 類型聲明
          • defer
          • goroutine
          • for-range

          明智地選擇你的函數(shù)參數(shù)

          我們盡量使用“小”參數(shù),因為它們的拷貝會被特別優(yōu)化。我們也嘗試在拷貝和GC的負載的與增長堆棧之間保持平衡。避免使用大量的參數(shù)——讓你的程序使用超快速的寄存器(寄存器的數(shù)量是有限的)

          聲明一個命名好的return結(jié)果

          這似乎比在函數(shù)體中聲明這些變量更高效。

          保存函數(shù)中間的結(jié)果

          幫助編譯器優(yōu)化你的代碼,保存中間結(jié)果,然后會有更多的選擇來優(yōu)化你的代碼。

          謹慎使用“defer”

          盡量不要使用 defer,或者至少 不要在循環(huán)中使用defer

          為“hot path”提供便利

          避免在這些地方分配內(nèi)存,尤其是短期對象。首先要檢查的的就是最常見的分支(if,switch)。

          這里 hot path在Go源碼中[2]也出現(xiàn)多次,根據(jù)在 sync.Once 的上下文中,“hot path”是什么意思?[3]中的回答,這里翻譯為熱路徑是非常頻繁執(zhí)行的指令序列。

          map優(yōu)化篇

          提前分配內(nèi)存

          一切都和其他地方一樣。初始化map時,指定其大小。

          使用空結(jié)構(gòu)作為值

          struct{}什么都不是,因此例如對信號值使用這種方法是非常有益的。

          清空map

          map只能增長,不能縮小。我們需要控制這一點——完全而明確地重置map。因為刪除其所有元素?zé)o濟于事。

          盡量不要在鍵和值中使用指針

          如果 map 不包含指針,那么 GC 就不會在它上面浪費寶貴的時間。而且要知道字符串也是指針——使用[]byte而不是字符串作為鍵。

          減少更改的次數(shù)

          同樣,我們不想使用指針,但我們可以使用 map 和 slice 的復(fù)合體,并將鍵存儲在 map 中,將可以不受限制地更改的值存儲在slice中。

          interface優(yōu)化篇

          計算內(nèi)存分配

          請記住,要給一個接口賦值,你首先需要將其拷貝到某處,然后粘貼一個指針。關(guān)鍵字是拷貝。事實證明,裝箱和拆箱的成本將近似于結(jié)構(gòu)體的大小和一次分配。

          選擇最佳的類型

          在某些情況下,裝箱/拆箱期間不會進行內(nèi)存分配。例如,比較小的和布爾值的變量和常量、具有一個簡單字段的struct、指針(包括map、chan、func

          避免內(nèi)存分配

          與其他地方一樣,我們盡量避免不必要的內(nèi)存分配。例如,將一個接口分配給一個接口,而不是裝箱兩次。

          僅在需要時使用

          避免在小型、頻繁調(diào)用的函數(shù)的參數(shù)和結(jié)果中使用接口。我們不需要額外的包裝和拆包。減少使用接口方法調(diào)用的頻率,哪怕只是因為它可以防止內(nèi)聯(lián)。

          指針、chan、BCE(Bounds Check Elimination-邊界檢查) 優(yōu)化篇

          避免不必要的解引用

          尤其是在循環(huán)中,因為事實證明它太昂貴了。解引用是我們不想以犧牲自己為代價執(zhí)行的一系列必要操作。

          channel使用效率是低效的

          使用channel會比其他同步方法慢。另外,select 中的 case 越多,我們的程序就越慢。但是select、case + default是優(yōu)化過了的。

          盡量避免不必要的邊界檢查

          這也很昂貴,我們應(yīng)該盡一切可能避免它。例如,一次檢查(獲取)最大slice索引比多次檢查更正確。最好是立即嘗試獲得極端的選項。

          總結(jié)

          在這篇文章中,我們看到了一些相同的優(yōu)化規(guī)則。

          幫助編譯器做出正確的決定。在編譯時分配內(nèi)存,使用中間結(jié)果,并盡量保持代碼的可讀性。

          不要忘記使用內(nèi)置的分析和trace跟蹤工具。

          最后小土也祝你在優(yōu)化的路上做到盡善盡美。

          參考資料

          [1]

          Golang: simple optimization notes: https://medium.com/scum-gazeta/golang-simple-optimization-notes-70bc64673980

          [2]

          hot path在Go源碼中: https://cs.opensource.google/search?q=%22hot%20path%22&ss=go%2Fgo

          [3]

          在 sync.Once 的上下文中,“hot path”是什么意思?: https://stackoverflow.com/questions/59174176/what-does-hot-path-mean-in-the-context-of-sync-once



          推薦閱讀


          福利

          我為大家整理了一份從入門到進階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進階看什么。關(guān)注公眾號 「polarisxu」,回復(fù) ebook 獲取;還可以回復(fù)「進群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 19
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产成人精品视频免费看 | 国产美女操B | 99精品一区二区 | 中文字幕不卡在线观看 | 男人天堂婷婷 |