<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Go 語言編譯器的 "//go:" 詳解

      【轉發(fā)】https://segmentfault.com/a/1190000016743220

      前言

      C 語言的 #include

      一上來不太好說明白 Go 語言里 //go: 是什么,我們先來看下非常簡單,也是幾乎每個寫代碼的人都知道的東西:C 語言的 #include
      我猜,大部分人第一行代碼都是 #include 吧。完整的就是#include <stdio.h>。意思很簡單,引入一個 stdio.h。誰引入?答案是編譯器。那么,# 字符的作用就是給 編譯器 一個 指示,讓編譯器知道接下來要做什么。

      編譯指示

      在計算機編程中,編譯指示(pragma)是一種語言結構,它指示編譯器應該如何處理其輸入。指示不是編程語言語法的一部分,因編譯器而異。

      這里 Wiki 詳細介紹了它,值得你看一下。

      Go 語言的編譯指示

      官方文檔 https://golang.org/cmd/compil...

      形如 //go: 就是 Go 語言編譯指示的實現(xiàn)方式。相信看過 Go SDK 的同學對此并不陌生,經(jīng)常能在代碼函數(shù)聲明的上一行看到這樣的寫法。
      有同學會問了,// 這不是注釋嗎?確實,它是以注釋的形式存在的。

      編譯器源碼 這里可以看到全部的指示,但是要注意,//go: 是連續(xù)的,// 和 go 之間并沒有空格。

      常用指示詳解

      //go:noinline

      noinline 顧名思義,不要內聯(lián)。

      Inline 內聯(lián)

      Inline,是在編譯期間發(fā)生的,將函數(shù)調用調用處替換為被調用函數(shù)主體的一種編譯器優(yōu)化手段。Wiki:Inline 定義

      使用 Inline 有一些優(yōu)勢,同樣也有一些問題。

      優(yōu)勢:
      • 減少函數(shù)調用的開銷,提高執(zhí)行速度。
      • 復制后的更大函數(shù)體為其他編譯優(yōu)化帶來可能性,如 過程間優(yōu)化
      • 消除分支,并改善空間局部性和指令順序性,同樣可以提高性能。
      問題:
      • 代碼復制帶來的空間增長。
      • 如果有大量重復代碼,反而會降低緩存命中率,尤其對 CPU 緩存是致命的。

      所以,在實際使用中,對于是否使用內聯(lián),要謹慎考慮,并做好平衡,以使它發(fā)揮最大的作用。
      簡單來說,對于短小而且工作較少的函數(shù),使用內聯(lián)是有效益的。

      內聯(lián)的例子

      func appendStr(word string) string {
          return "new " + word
      }

      執(zhí)行 GOOS=linux GOARCH=386 go tool compile -S main.go > main.S
      我截取有區(qū)別的部分展出它編譯后的樣子:

          0x0015 00021 (main.go:4)    LEAL    ""..autotmp_3+28(SP), AX
          0x0019 00025 (main.go:4)    PCDATA    $2, $0
          0x0019 00025 (main.go:4)    MOVL    AX, (SP)
          0x001c 00028 (main.go:4)    PCDATA    $2, $1
          0x001c 00028 (main.go:4)    LEAL    go.string."new "(SB), AX
          0x0022 00034 (main.go:4)    PCDATA    $2, $0
          0x0022 00034 (main.go:4)    MOVL    AX, 4(SP)
          0x0026 00038 (main.go:4)    MOVL    $4, 8(SP)
          0x002e 00046 (main.go:4)    PCDATA    $2, $1
          0x002e 00046 (main.go:4)    LEAL    go.string."hello"(SB), AX
          0x0034 00052 (main.go:4)    PCDATA    $2, $0
          0x0034 00052 (main.go:4)    MOVL    AX, 12(SP)
          0x0038 00056 (main.go:4)    MOVL    $5, 16(SP)
          0x0040 00064 (main.go:4)    CALL    runtime.concatstring2(SB)

      可以看到,它并沒有調用 appendStr 函數(shù),而是直接把這個函數(shù)體的功能內聯(lián)了。

      那么話說回來,如果你不想被內聯(lián),怎么辦呢?此時就該使用 go//:noinline 了,像下面這樣寫:

      //go:noinline
      func appendStr(word string) string {
          return "new " + word
      }

      編譯后是:

          0x0015 00021 (main.go:4)    LEAL    go.string."hello"(SB), AX
          0x001b 00027 (main.go:4)    PCDATA    $2, $0
          0x001b 00027 (main.go:4)    MOVL    AX, (SP)
          0x001e 00030 (main.go:4)    MOVL    $5, 4(SP)
          0x0026 00038 (main.go:4)    CALL    "".appendStr(SB)

      此時編譯器就不會做內聯(lián),而是直接調用 appendStr 函數(shù)。

      //go:nosplit

      nosplit 的作用是:跳過棧溢出檢測。

      棧溢出是什么?

      正是因為一個 Goroutine 的起始棧大小是有限制的,且比較小的,才可以做到支持并發(fā)很多 Goroutine,并高效調度。
      stack.go 源碼中可以看到,_StackMin 是 2048 字節(jié),也就是 2k,它不是一成不變的,當不夠用時,它會動態(tài)地增長。
      那么,必然有一個檢測的機制,來保證可以及時地知道棧不夠用了,然后再去增長。
      回到話題,nosplit 就是將這個跳過這個機制。

      優(yōu)劣

      顯然地,不執(zhí)行棧溢出檢查,可以提高性能,但同時也有可能發(fā)生 stack overflow 而導致編譯失敗。

      //go:noescape

      noescape 的作用是:禁止逃逸,而且它必須指示一個只有聲明沒有主體的函數(shù)。

      逃逸是什么?

      Go 相比 C、C++ 是內存更為安全的語言,主要一個點就體現(xiàn)在它可以自動地將超出自身生命周期的變量,從函數(shù)棧轉移到堆中,逃逸就是指這種行為。

      請參考我之前的文章,逃逸分析

      優(yōu)劣

      最顯而易見的好處是,GC 壓力變小了。
      因為它已經(jīng)告訴編譯器,下面的函數(shù)無論如何都不會逃逸,那么當函數(shù)返回時,其中的資源也會一并都被銷毀。
      不過,這么做代表會繞過編譯器的逃逸檢查,一旦進入運行時,就有可能導致嚴重的錯誤及后果。

      //go:norace

      norace 的作用是:跳過競態(tài)檢測
      我們知道,在多線程程序中,難免會出現(xiàn)數(shù)據(jù)競爭,正常情況下,當編譯器檢測到有數(shù)據(jù)競爭,就會給出提示。如:

      var sum int
      
      func main() {
          go add()
          go add()
      }
      
      func add() {
          sum++
      }

      執(zhí)行 go run -race main.go 利用 -race 來使編譯器報告數(shù)據(jù)競爭問題。你會看到:

      ==================
      WARNING: DATA RACE
      Read at 0x00000112f470 by goroutine 6:
        main.add()
            /Users/sxs/Documents/go/src/test/main.go:15 +0x3a
      
      Previous write at 0x00000112f470 by goroutine 5:
        main.add()
            /Users/sxs/Documents/go/src/test/main.go:15 +0x56
      
      Goroutine 6 (running) created at:
        main.main()
            /Users/sxs/Documents/go/src/test/main.go:11 +0x5a
      
      Goroutine 5 (finished) created at:
        main.main()
            /Users/sxs/Documents/go/src/test/main.go:10 +0x42
      ==================
      Found 1 data race(s)

      說明兩個 goroutine 執(zhí)行的 add() 在競爭。

      優(yōu)劣

      使用 norace 除了減少編譯時間,我想不到有其他的優(yōu)點了。但缺點卻很明顯,那就是數(shù)據(jù)競爭會導致程序的不確定性。

      總結

      我認為絕大多數(shù)情況下,無需在編程時使用 //go: Go 語言的編譯器指示,除非你確認你的程序的性能瓶頸在編譯器上,否則你都應該先去關心其他更可能出現(xiàn)瓶頸的事情。

      參考

      posted @ 2025-03-14 00:36  siduoge2  閱讀(32)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久人人爽人人爽人人片av| 丰满人妻无码∧v区视频| 无遮无挡爽爽免费视频| 无码熟妇人妻av在线电影| 国产一区二区日韩在线| 在线观看中文字幕国产码| 日韩高清亚洲日韩精品一区二区| 精品无码国产污污污免费| 国产精品久久蜜臀av| 国产精品香港三级国产av| 国产线播放免费人成视频播放| 40岁成熟女人牲交片20分钟| 精品精品亚洲高清a毛片| 国产成人精品久久一区二| 亚洲av麻豆aⅴ无码电影| 日本精品一区二区不卡| 色综合色综合久久综合频道| 亚洲av成人一区在线| 99re6在线视频精品免费下载| 亚洲av无码牛牛影视在线二区 | 国产亚洲精品第一综合另类无码无遮挡又大又爽又黄的视频 | 好紧好滑好湿好爽免费视频| 男人扒女人添高潮视频| 日韩av一区二区三区精品| gogogo高清在线观看视频中文 | 神马久久亚洲一区 二区| 免费国产黄线在线观看| 伊人精品成人久久综合| 无码国产精品一区二区av| 国产精品一区二区三区麻豆| 亚洲人成网网址在线看| 国产人妻人伦精品婷婷| 日韩AV高清在线看片| 南康市| 久久毛片少妇高潮| 日韩中文字幕亚洲精品 | 国产亚洲久久久久久久| 久操热在线视频免费观看| 久久精品道一区二区三区| 国产免费久久精品44| 久久这里只精品热免费99|