成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go 1.19 相比 Go 1.18 有哪些值得注意的改動?

開發(fā) 前端
這些改變主要影響性能(??switch?? 優(yōu)化)、構建系統(tǒng)的維護者(需要調整對編譯器/匯編器的直接調用)以及調試信息格式的標準化。對于大多數(shù)使用 ??go build?? 的開發(fā)者來說,后兩項更改是透明的。

https://go.dev/doc/go1.19

Go 1.19 值得關注的改動:

  1. 內存模型與原子操作 : Go 的 內存模型(memory model) 已更新,與 C、C++、Java 等語言的 模型 對齊,以確保持續(xù)一致性。同時,sync/atomic 包引入了新的 原子類型(atomic types),如 atomic.Int64 和 atomic.Pointer[T],簡化了原子操作并提高了類型安全性。
  2. go 命令 : 改進了構建信息的包含(-trimpath)、go generate/test 的環(huán)境一致性、go env 的輸出處理,并增強了 go list -json 的靈活性和性能,同時緩存了部分模塊加載信息以加速 go list
  3. vet 工具 : 新增檢查,用于發(fā)現(xiàn) errors.As 的第二個參數(shù)誤用 *error 類型的常見錯誤。
  4. Runtime : 引入了 軟內存限制(soft memory limit),可通過 GOMEMLIMIT 環(huán)境變量或 runtime/debug.SetMemoryLimit 函數(shù)進行設置,允許程序在接近內存上限時更有效地利用資源,并與 GOGC 協(xié)同工作。
  5. 編譯器、匯編器與鏈接器 : 編譯器通過 跳轉表(jump table) 優(yōu)化了大型 switch 語句(在 amd64 和 arm64 架構下提速約 20%);編譯器和匯編器現(xiàn)在強制要求 -p=importpath 標志來構建可鏈接的對象文件;鏈接器在 ELF 平臺使用標準的壓縮 DWARF 格式。

下面是一些值得展開的討論:

Go 1.19 修訂內存模型并引入新的原子類型

Go 1.19 對其內存模型進行了修訂,主要目標是與 C, C++, Java, JavaScript, Rust, 和 Swift 等主流語言使用的內存模型保持一致。需要注意的是,Go 僅提供 順序一致(sequentially consistent) 的原子操作,而不支持其他語言中可能存在的更寬松的內存排序形式。

伴隨著內存模型的更新,sync/atomic 包引入了一系列新的原子類型,包括 atomic.Boolatomic.Int32atomic.Int64atomic.Uint32atomic.Uint64atomic.Uintptr, 和 atomic.Pointer[T]

這些新類型的主要優(yōu)勢在于:

  1. 類型安全 :它們封裝了底層的值,強制所有訪問都必須通過原子 API 進行,避免了意外的非原子讀寫操作。
  2. 簡化指針操作 :atomic.Pointer[T] 泛型類型避免了在調用點將指針轉換為 unsafe.Pointer 的需要,使得代碼更清晰、更安全。
  3. 自動對齊 :atomic.Int64 和 atomic.Uint64 類型在結構體中或分配內存時,即使在 32 位系統(tǒng)上也會自動保證 64 位對齊。這對于保證原子操作的正確性至關重要。

舊方式(Go 1.18 及之前)

通常需要直接使用 sync/atomic 包提供的函數(shù),并對基本類型進行操作。例如,對一個共享的 int64 變量進行原子更新:

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    var counter int64
    var wg sync.WaitGroup

    // 啟動多個 goroutine 并發(fā)增加 counter
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            // 使用 atomic 函數(shù)進行原子增操作
            atomic.AddInt64(&counter, 1)
        }()
    }

    wg.Wait()

    // 使用 atomic 函數(shù)進行原子讀操作
    finalValue := atomic.LoadInt64(&counter)
    fmt.Println("Final counter:", finalValue) // 輸出: Final counter: 100
}

對于指針類型,之前可能需要 atomic.Value 或者結合 unsafe.Pointer 使用 atomic.LoadPointer/StorePointer

新方式(Go 1.19 及之后)

使用新的原子類型,代碼更簡潔,類型約束更強。

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    // 使用新的 atomic.Int64 類型
    var counter atomic.Int64
    var wg sync.WaitGroup

    // 啟動多個 goroutine 并發(fā)增加 counter
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            // 直接調用類型的方法進行原子增操作
            counter.Add(1)
        }()
    }

    wg.Wait()

    // 直接調用類型的方法進行原子讀操作
    finalValue := counter.Load()
    fmt.Println("Final counter:", finalValue) // 輸出: Final counter: 100
}

對于指針,atomic.Pointer[T] 提供了類型安全的原子讀寫能力:

package main

import (
    "fmt"
    "sync/atomic"
)

type Config struct {
    Version string
    Data    map[string]string
}

func main() {
    var currentConfig atomic.Pointer[Config]

    // 初始化配置
    initialConfig := &Config{Version: "v1", Data: map[string]string{"key": "value1"}}
    currentConfig.Store(initialConfig)

    // 讀取配置
    cfg1 := currentConfig.Load()
    fmt.Printf("Config v%s: %v\n", cfg1.Version, cfg1.Data)

    // 原子地更新配置
    newConfig := &Config{Version: "v2", Data: map[string]string{"key": "value2", "new": "added"}}
    currentConfig.Store(newConfig)

    cfg2 := currentConfig.Load()
    fmt.Printf("Config v%s: %v\n", cfg2.Version, cfg2.Data)
}
Config vv1: map[key:value1]
Config vv2: map[key:value2 new:added]

這種方式相比舊的 atomic.Value 或 unsafe.Pointer 操作,類型更安全,意圖更明確。

go 命令的改進

Go 1.19 對 go 命令進行了多項增強和調整,主要涉及構建過程、環(huán)境設置、信息查詢等方面。

  • -trimpath 標志信息嵌入 :如果在 go build 時設置了 -trimpath 標志(用于從編譯出的二進制文件中移除本地構建路徑信息),這個設置現(xiàn)在會被記錄在二進制文件的構建信息中。可以通過 go version -m <binary> 或 debug.ReadBuildInfo 來查看。
# 編譯時加入 -trimpath
go build -trimpath -o myapp main.go

# 查看二進制文件的構建信息
go version -m ./myapp
# 輸出會包含類似 build -trimpath=true 的信息
  • go generate 明確設置 GOROOT :現(xiàn)在 go generate 會在其執(zhí)行子進程的環(huán)境變量中明確設置 GOROOT。這確保了即使代碼生成器本身是使用 -trimpath 構建的(可能導致其無法自動找到 GOROOT),它也能定位到正確的 Go 安裝根目錄。
  • go test 和 go generate 的 PATH 調整 :這兩個命令現(xiàn)在會將 $GOROOT/bin 放在子進程 PATH 環(huán)境變量的開頭。這樣做可以保證當測試代碼或代碼生成器需要執(zhí)行 go 命令時,它們會調用到與父進程相同版本的 go 工具鏈,避免潛在的版本沖突。
  • go env 輸出的空格處理 :對于包含空格的環(huán)境變量值(如 CGO_CFLAGSCGO_CPPFLAGSCGO_CXXFLAGSCGO_FFLAGSCGO_LDFLAGSGOGCCFLAGS),go env 現(xiàn)在會在輸出時給它們加上引號,使得輸出結果更易于被腳本等其他工具解析。
  • go list -json 支持字段選擇 :go list -json 命令現(xiàn)在可以接受一個逗號分隔的字段列表,用于指定需要輸出的 JSON 字段。如果指定了列表,go list 只會計算和輸出這些字段,這在某些情況下可以顯著提高性能,因為它避免了計算不需要的字段。這也可能抑制某些只在計算未請求字段時才會出現(xiàn)的錯誤。
# 僅獲取當前模塊的導入路徑和直接依賴
go list -json=ImportPath,Deps .
  • go list 模塊加載緩存 :go 命令現(xiàn)在會緩存加載某些模塊所需的信息,這有望加速部分 go list 命令的調用。

vet 工具新增 errors.As 使用檢查

vet 工具的 errorsas 檢查器現(xiàn)在增加了一項功能:檢測 errors.As 函數(shù)的第二個參數(shù)是否被錯誤地傳遞了 *error 類型。這是一個常見的錯誤。

errors.As 函數(shù)用于檢查錯誤鏈中是否存在特定類型的錯誤,并將其賦值給一個變量。其簽名如下:

func As(err error, target interface{}) bool

正確的用法是,target 參數(shù)必須是一個指向 具體錯誤類型 的指針,或者是一個指向實現(xiàn)了 error 接口的任意類型的指針。errors.As 會遍歷 err 的錯誤鏈,如果找到一個錯誤可以賦值給 target 指向的變量,就進行賦值并返回 true

常見的錯誤用法

開發(fā)者有時可能會錯誤地傳遞一個 *error (指向 error 接口的指針)給 target

package main

import (
    "errors"
    "fmt"
    "os"
)

func main() {
    // 示例錯誤,包裝了 *os.PathError
    err := fmt.Errorf("wrapping a file error: %w", &os.PathError{Op: "open", Path: "/no/such/file", Err: errors.New("file not found")})

    var genericErr error // 聲明一個 error 接口類型的變量
    // 錯誤用法:將 *error 類型的指針傳遞給 errors.As
    // 這幾乎永遠不是你想要的,因為它只會檢查錯誤鏈中是否有某個值可以賦給一個 error 接口
    // 這通常沒有意義,因為鏈中的任何錯誤都可以賦值給 error 接口
    if errors.As(err, &genericErr) {
        // 這段代碼幾乎總會執(zhí)行 (只要 err != nil),但 genericErr 會被賦值為鏈中的第一個錯誤
        // 這并不是 errors.As 的設計意圖
        fmt.Printf("Found an error (incorrectly): %v\n", genericErr)
    } else {
        fmt.Println("No error found (incorrectly)")
    }
}
piperliu@go-x86:~/code/playground$ go run main.go 
Found an error (incorrectly): wrapping a file error: open /no/such/file: file not found
piperliu@go-x86:~/code/playground$ go vet main.go 
# command-line-arguments
./main.go:17:8: second argument to errors.As should not be *error

Go 1.19 的 vet 會對上述錯誤用法發(fā)出警告。

正確的用法

應該傳遞一個指向 具體錯誤類型 變量的指針。

package main

import (
    "errors"
    "fmt"
    "os"
)

func main() {
    // 示例錯誤,包裝了 *os.PathError
    err := fmt.Errorf("wrapping a file error: %w", &os.PathError{Op: "open", Path: "/no/such/file", Err: errors.New("file not found")})

    var pathErr *os.PathError // 聲明一個具體錯誤類型的指針變量
    // 正確用法:傳遞 *os.PathError 類型的指針
    if errors.As(err, &pathErr) {
        // 如果錯誤鏈中存在 *os.PathError 類型的錯誤,pathErr 會被賦值
        fmt.Printf("Successfully found PathError: Op=%s, Path=%s\n", pathErr.Op, pathErr.Path)
    } else {
        fmt.Println("PathError not found in chain")
    }
}
go run main.go 
Successfully found PathError: Op=open, Path=/no/such/file
piperliu@go-x86:~/code/playground$ go vet main.go

這個新的 vet 檢查有助于開發(fā)者及早發(fā)現(xiàn)并修正這種對 errors.As 的誤用。

Runtime 的軟內存限制及其他改進

Go 1.19 在 Runtime 層面引入了重要的 軟內存限制(soft memory limit) 功能,并包含其他多項優(yōu)化。

軟內存限制

  • 目的 :提供一種機制來限制 Go 程序使用的總內存量,以提高在容器化環(huán)境等資源受限場景下的資源利用率。
  • 范圍 :這個限制覆蓋 Go 堆(heap)以及所有由 Runtime 管理的內存(例如 goroutine 棧、GC 元數(shù)據(jù)等)。它 不包括 程序二進制文件本身的內存映射、其他語言(如 C)管理的內存,以及操作系統(tǒng)為 Go 程序保留的內存(如某些內核緩沖區(qū))。
  • 配置 :可以通過設置 GOMEMLIMIT 環(huán)境變量(例如 GOMEMLIMIT=1024MiB)或在代碼中調用 runtime/debug.SetMemoryLimit(limit int64) 來管理。
  • 與 GOGC 的關系 :軟內存限制與 GOGC(或 runtime/debug.SetGCPercent)協(xié)同工作。即使設置 GOGC=off,只要設置了 GOMEMLIMIT,Runtime 仍然會嘗試遵守這個內存限制,通過更頻繁地觸發(fā) GC 來控制內存增長。這使得程序能夠始終最大限度地利用其被分配的內存限額。
  • GC CPU 限制器 :當程序的活動堆大小接近軟內存限制時,為了防止 GC 過于頻繁(稱為 GC 抖動/thrashing)而嚴重影響程序性能,Runtime 會嘗試將 GC 的 CPU 利用率限制在 50% 以內(不包括空閑時間)。這意味著 Runtime 寧愿稍微超出內存限制,也不愿完全阻止應用程序的進展。可以通過新的 運行指標(runtime metric) /gc/limiter/last-enabled:gc-cycle 查看該限制器最后一次生效的 GC 周期。
  • 穩(wěn)定性與限制 :對于較大的內存限制(數(shù)百 MB 或更多),該功能是穩(wěn)定且生產(chǎn)就緒的。但對于非常小的限制(幾十 MB 或更少),由于外部延遲因素(如操作系統(tǒng)調度)的影響,限制可能不那么精確(詳見 issue 52433)。

其他 Runtime 改進

  • 空閑狀態(tài)下的 GC 工作線程 :當應用程序足夠空閑以至于觸發(fā)周期性 GC 時,Runtime 現(xiàn)在會調度更少的 GC 工作 goroutine 在空閑的操作系統(tǒng)線程上運行,以減少不必要的資源消耗。
  • 初始 Goroutine 棧大小 :Runtime 現(xiàn)在會根據(jù) goroutine 歷史平均棧使用量來分配初始棧大小。這旨在減少平均情況下早期棧增長和復制的開銷,代價是對于棧使用量遠低于平均值的 goroutine 可能會浪費最多 2 倍的空間。
  • Unix 文件描述符限制(RLIMIT_NOFILE) :在 Unix 操作系統(tǒng)上,導入了 os 包的 Go 程序現(xiàn)在會自動將進程的打開文件描述符軟限制(soft limit)提高到硬限制(hard limit)允許的最大值。這是為了解決某些系統(tǒng)上為了兼容舊的 C 程序(使用 select 系統(tǒng)調用)而設置的過低的人為限制。Go 程序(尤其是并發(fā)處理大量文件時,如 gofmt)經(jīng)常因此耗盡文件描述符。此更改的一個潛在影響是,如果 Go 程序再啟動舊的 C 程序作為子進程,這些子進程可能會以過高的文件描述符限制運行。這可以通過在啟動 Go 程序之前設置較低的硬限制來解決。
  • 簡化不可恢復錯誤的回溯信息 :對于不可恢復的致命錯誤(如并發(fā) map 寫入、解鎖未鎖定的互斥鎖),現(xiàn)在默認打印更簡潔的回溯信息,不包含 Runtime 的元數(shù)據(jù)(類似于 panic 的致命錯誤)。除非設置了 GOTRACEBACK=system 或 crash,才會打印包含完整元數(shù)據(jù)的詳細回溯信息。Runtime 內部的致命錯誤總是包含完整元數(shù)據(jù)。
  • 調試器注入函數(shù)調用(ARM64) :在 ARM64 架構上增加了對調試器注入函數(shù)調用的支持。這使得開發(fā)者在使用支持此功能的更新版調試器時,可以在交互式調試會話中調用程序中的函數(shù)。
  • 地址消毒器(Address Sanitizer)改進 :Go 1.18 中引入的 地址消毒器(address sanitizer) 支持現(xiàn)在能更精確地處理函數(shù)參數(shù)和全局變量。

編譯器、匯編器與鏈接器的更新

Go 1.19 在構建工具鏈的底層組件方面也有一些重要的變化。

編譯器 (Compiler)

  • 大型 switch 語句優(yōu)化 :編譯器現(xiàn)在使用 跳轉表(jump table) 來實現(xiàn)包含大量 case 的整數(shù)和字符串 switch 語句。這可以帶來顯著的性能提升,根據(jù)具體情況,速度可能提高約 20%。此優(yōu)化目前僅適用于 GOARCH=amd64 和 GOARCH=arm64 架構。

例如,一個有許多字符串 case 的 switch

func handleCommand(cmd string) {
    switch cmd {
    case "START":
        // ...
    case "STOP":
        // ...
    case "RESTART":
        // ...
    // ... 很多其他 case ...
    case "STATUS":
        // ...
    default:
        // ...
    }
}

在 Go 1.19 中,如果這個 switch 足夠大,編譯器(在支持的架構上)會生成更高效的跳轉表代碼,而不是一系列的比較和跳轉。

  • 強制要求 -p=importpath 標志 :Go 編譯器現(xiàn)在要求必須提供 -p=importpath 標志才能構建一個可鏈接的對象文件 (.o 文件)。go build 命令和 Bazel 構建系統(tǒng)已經(jīng)會自動提供這個標志。如果你有自定義的構建系統(tǒng)直接調用 Go 編譯器(compile),你需要確保傳遞了這個標志。importpath 通常是包的導入路徑。
  • 移除 -importmap 標志 :Go 編譯器不再接受 -importmap 標志。直接調用編譯器的構建系統(tǒng)必須改為使用 -importcfg 標志來提供導入路徑到實際文件路徑的映射。go build 會自動處理這個。

匯編器 (Assembler)

  • 強制要求 -p=importpath 標志 :與編譯器類似,Go 匯編器(asm)現(xiàn)在也要求必須提供 -p=importpath 標志才能構建可鏈接的對象文件。同樣,go build 會處理好,但直接調用匯編器的系統(tǒng)需要自行添加。

鏈接器 (Linker)

  • ELF 平臺使用標準壓縮 DWARF 格式 :在 ELF 格式的目標平臺(如 Linux)上,鏈接器現(xiàn)在默認使用標準的 gABI 格式(SHF_COMPRESSED)來壓縮 DWARF 調試信息段,取代了之前使用的非標準的 .zdebug 格式。這有助于提高與其他工具鏈(如 GDB、objdump 等)的兼容性。

這些改變主要影響性能(switch 優(yōu)化)、構建系統(tǒng)的維護者(需要調整對編譯器/匯編器的直接調用)以及調試信息格式的標準化。對于大多數(shù)使用 go build 的開發(fā)者來說,后兩項更改是透明的。

責任編輯:武曉燕 來源: Piper蛋窩
相關推薦

2025-04-30 09:02:46

2025-04-28 08:00:56

2025-04-17 08:00:48

2025-04-14 08:06:04

2025-04-25 08:01:12

Go應用程序部署

2025-04-15 08:00:53

2025-04-18 08:07:12

2025-05-06 05:00:00

2025-05-06 08:00:35

2025-05-06 00:00:08

2025-04-21 00:05:00

2025-04-23 08:02:40

2025-04-21 08:00:56

2025-04-24 09:01:46

2025-04-27 08:00:35

2025-04-21 00:00:00

Go 開發(fā)Go 語言Go 1.9

2025-04-22 08:02:23

2025-04-14 00:00:04

2025-04-27 00:00:01

Go 1.16Go 1.15接口

2025-04-11 08:02:38

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久艹av| 最新av在线播放 | 免费黄色a级毛片 | 日韩视频一区二区 | 久久久久网站 | 欧美日韩专区 | 成人av一区二区三区 | 黄色一级大片在线免费看产 | 中文字幕亚洲精品在线观看 | 日本视频中文字幕 | 成人综合在线视频 | 亚洲精品成人 | 国产一二三区在线 | 成年人在线观看视频 | 日日夜夜精品免费视频 | 欧美性生活视频 | 欧美日韩亚洲系列 | 美女黄网 | 欧美日韩国产三级 | 91中文字幕在线观看 | 国产91在线 | 亚洲 | 成人免费视屏 | 欧美激情视频一区二区三区在线播放 | 国产美女自拍视频 | 午夜男人免费视频 | 日韩欧美一区二区三区四区 | 欧美日韩中文在线观看 | 久久88| 国产在线小视频 | 日韩一区在线播放 | 久久激情五月丁香伊人 | 午夜噜噜噜 | 久久久www成人免费精品 | 精品国产一区二区国模嫣然 | 91精品国产91综合久久蜜臀 | 亚洲精品一区二区三区蜜桃久 | 国产日韩视频 | 国产美女久久 | 国产高清免费视频 | 午夜影院视频 | 在线色网站 |