自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從DevOps到日常腳本:聊聊Go語(yǔ)言的多面性

開(kāi)發(fā) 前端
在本文中,我們探討了Go語(yǔ)言在DevOps和日常腳本編寫中的多面性。首先,Go語(yǔ)言因其高性能、并發(fā)處理能力及跨平臺(tái)編譯特性,成為DevOps領(lǐng)域的重要工具,助力于自動(dòng)化任務(wù)和微服務(wù)部署。

2024年初,TIOBE編程語(yǔ)言排行榜上,Go再次進(jìn)入了前十,并在之后又成功沖高至第七名。

Go語(yǔ)言的排名上升,至少在Reddit Go論壇[1]上帖子數(shù)量和在線人數(shù)上得到了體現(xiàn),盡管目前與Rust[2]熱度仍有差距,但可見(jiàn)Go的關(guān)注度在提升:

圖片

2024年國(guó)慶節(jié)假期某天下午的實(shí)時(shí)在線數(shù)對(duì)比

隨著Go語(yǔ)言人氣的上升,論壇中的問(wèn)題也變得愈發(fā)多樣化。許多Gopher常常問(wèn)及為何Go是DevOps語(yǔ)言[3]和Go適合用作腳本語(yǔ)言嗎[4]等問(wèn)題,這些都反映了Go語(yǔ)言的多面性。

從最初的系統(tǒng)編程語(yǔ)言,到如今在DevOps領(lǐng)域的廣泛應(yīng)用,再到一些場(chǎng)合被探索用作腳本語(yǔ)言,Go展現(xiàn)出了令人驚嘆的靈活性和適應(yīng)性。在本篇文章中,我們將聚焦于Go語(yǔ)言在DevOps領(lǐng)域的應(yīng)用以及它作為腳本替代語(yǔ)言的潛力,聊聊其強(qiáng)大多面性如何滿足這些特定場(chǎng)景的需求。

1. Go在DevOps中的優(yōu)勢(shì)

隨著DevOps的發(fā)展,平臺(tái)工程(Platform Engineering)[5]這一新興概念逐漸興起。在自動(dòng)化任務(wù)、微服務(wù)部署和系統(tǒng)管理中,編程語(yǔ)言的作用變得愈發(fā)重要。Go語(yǔ)言憑借其高性能、并發(fā)處理能力以及能夠編譯成單一二進(jìn)制文件的特點(diǎn),越來(lái)越受到DevOps領(lǐng)域開(kāi)發(fā)人員的青睞,成為開(kāi)發(fā)DevOps工具鏈的重要組成部分。

首先,Go的跨平臺(tái)編譯能力使得DevOps團(tuán)隊(duì)可以在一個(gè)平臺(tái)上編譯,然后在多個(gè)不同的操作系統(tǒng)和架構(gòu)上運(yùn)行,結(jié)合編譯出的單一可執(zhí)行文件的能力,大大簡(jiǎn)化了部署流程,這也是很多Go開(kāi)發(fā)者認(rèn)為Go適合DevOps的第一優(yōu)勢(shì):

$GOOS=linux GOARCH=amd64 go build -o myapp-linux-amd64 main.go
$GOOS=linux GOARCH=arm64 go build -o myapp-linux-arm64 main.go
$GOOS=darwin GOARCH=amd64 go build -o myapp-darwin-amd64 main.go
$GOOS=windows GOARCH=amd64 go build -o myapp-windows-amd64.exe main.go

其次,Go的標(biāo)準(zhǔn)庫(kù)仿佛“瑞士軍刀”,開(kāi)箱即用,為DevOps場(chǎng)景提供了所需的豐富的網(wǎng)絡(luò)、加密和系統(tǒng)操作功能庫(kù),大幅降低對(duì)外部的依賴,即便不使用第三方包生態(tài)系統(tǒng),也可以滿足大部分的DevOps功能需求。

此外,Go的goroutines和channels為處理高并發(fā)任務(wù)提供了極大便利,這在DevOps中也尤為重要。例如,以下代碼展示了如何使用goroutines并發(fā)檢查多個(gè)服務(wù)的健康狀態(tài):

func checkServices(services []string) {
    var wg sync.WaitGroup
    for _, service := range services {
        wg.Add(1)
        go func(s string) {
            defer wg.Done()
            if err := checkHealth(s); err != nil {
                log.Printf("Service %s is unhealthy: %v", s, err)
            } else {
                log.Printf("Service %s is healthy", s)
            }
        }(service)
    }
    wg.Wait()
}

并且,許多知名的DevOps基礎(chǔ)設(shè)施、中間件和工具都是用Go編寫的,如Docker、Kubernetes、Prometheus等,集成起來(lái)非常絲滑。這些工具的成功進(jìn)一步證明了Go在DevOps領(lǐng)域的適用性。

2. Go作為腳本語(yǔ)言的潛力

在傳統(tǒng)的DevOps任務(wù)中,Python和Shell腳本長(zhǎng)期以來(lái)都是主力軍,它們(尤其是Python)以其簡(jiǎn)潔的語(yǔ)法和豐富的生態(tài)系統(tǒng)贏得了DevOps社區(qū)的廣泛青睞。然而,傳統(tǒng)主力Python和Shell腳本雖然靈活易用,但在處理大規(guī)模數(shù)據(jù)或需要高性能的場(chǎng)景時(shí)往往力不從心。此外,它們的動(dòng)態(tài)類型系統(tǒng)可能導(dǎo)致運(yùn)行時(shí)錯(cuò)誤,增加了調(diào)試難度。

隨著Go的普及,它的“超高性價(jià)比”逐漸被開(kāi)發(fā)運(yùn)維人員所接受:既有著接近于腳本語(yǔ)言的較低的學(xué)習(xí)曲線與較高的生產(chǎn)力(也得益于Go超快的編譯速度),又有著靜態(tài)語(yǔ)言的高性能,還有單一文件在部署方面的便利性。

下面是一個(gè)簡(jiǎn)單的文件處理腳本,用于向大家展示Go的簡(jiǎn)單易學(xué):

package main

import (
 "bufio"
 "fmt"
 "os"
 "strings"
)

func main() {
 file, err := os.Open("input.txt")
 if err != nil {
  fmt.Println("Error opening file:", err)
  return
 }
 defer file.Close()

 scanner := bufio.NewScanner(file)
 for scanner.Scan() {
  line := scanner.Text()
  if strings.Contains(line, "ERROR") {
   fmt.Println(line)
  }
 }
}

這個(gè)示例雖然要比同等功能的Python或shell代碼行數(shù)要多,但由于Go的簡(jiǎn)單和直觀,多數(shù)人都很容易看懂這段代碼。

此外,Go的靜態(tài)強(qiáng)類型系統(tǒng)可以在編譯時(shí)捕獲更多錯(cuò)誤,避免在運(yùn)行時(shí)的調(diào)試,提高了腳本在運(yùn)行時(shí)的可靠性。

開(kāi)發(fā)運(yùn)維人員眼中的腳本語(yǔ)言,如Shell腳本和Python腳本,通常是直接基于源代碼進(jìn)行解釋和運(yùn)行的。實(shí)際上,Go語(yǔ)言同樣可以實(shí)現(xiàn)這一點(diǎn),而其關(guān)鍵工具就是go run命令。這個(gè)命令允許開(kāi)發(fā)者快速執(zhí)行Go代碼,從而使Go源碼看起來(lái)更像是“腳本”,下面我們就來(lái)看看go run。

3. go run:橋接編譯型語(yǔ)言與腳本語(yǔ)言的利器

我們知道go run命令實(shí)際上是編譯和運(yùn)行的組合,它首先編譯源代碼,然后立即執(zhí)行生成的二進(jìn)制文件。這個(gè)過(guò)程對(duì)用戶來(lái)說(shuō)是透明的,使得Go程序可以像腳本一樣方便地運(yùn)行。這一命令也大大簡(jiǎn)化了Go程序的開(kāi)發(fā)流程,使Go更接近傳統(tǒng)的腳本語(yǔ)言工作流??梢哉f(shuō),通過(guò)go run,Go語(yǔ)言向腳本語(yǔ)言的使用體驗(yàn)更靠近了一步。

此外,go run與go build在編譯階段的行為并不完全相同:

  • go run在運(yùn)行結(jié)束后,不保留編譯后的二進(jìn)制文件;而go build生成可執(zhí)行文件并保留。
  • go run編譯時(shí)默認(rèn)不包含調(diào)試信息,以減少構(gòu)建時(shí)間;而go build則保留完整的調(diào)試信息。
  • go run可以使用-exec標(biāo)志指定運(yùn)行環(huán)境,比如:
$go run -exec="ls" main.go
/var/folders/cz/sbj5kg2d3m3c6j650z0qfm800000gn/T/go-build1742641170/b001/exe/main

我們看到,如果設(shè)置了-exec標(biāo)志,那么go run -exec="prog" main.go args編譯后的命令執(zhí)行就變?yōu)榱?prog a.out args"。go run還支持跨平臺(tái)模擬執(zhí)行,當(dāng)GOOS或GOARCH與系統(tǒng)默認(rèn)值不同時(shí),如果在PATH路徑下存在名為"go_GOOS_$GOARCH_exec"的程序,那么go run就會(huì)執(zhí)行:

$go_$GOOS_$GOARCH_exec a.out args

比如:go_js_wasm_exec a.out args
  • go run通常用于運(yùn)行main包,在go module開(kāi)啟的情況下,go run使用的是main module的上下文。go build可以編譯多個(gè)包,對(duì)于非main包時(shí)只檢查構(gòu)建而不生成輸出
  • go run還支持運(yùn)行一個(gè)指定版本號(hào)的包

當(dāng)指定了版本后綴(如@v1.0.0或@latest)時(shí),go run會(huì)進(jìn)入module-aware mode(模塊感知模式),并忽略當(dāng)前目錄或上級(jí)目錄中的go.mod文件。這意味著,即使你當(dāng)前的項(xiàng)目中存在依賴管理文件go.mod,go run也不會(huì)影響或修改當(dāng)前項(xiàng)目的依賴關(guān)系,下面這個(gè)示例展示了這一點(diǎn):

$go run golang.org/x/example/hello@latest

go: downloading golang.org/x/example v0.0.0-20240925201653-1a5e218e5455
go: downloading golang.org/x/example/hello v0.0.0-20240925201653-1a5e218e5455
Hello, world!

這個(gè)功能特別適合在不影響主模塊依賴的情況下,臨時(shí)運(yùn)行某個(gè)工具或程序。例如,如果你只是想測(cè)試某個(gè)工具的特定版本,或者快速運(yùn)行一個(gè)遠(yuǎn)程程序包,而不希望它干擾你正在開(kāi)發(fā)的項(xiàng)目中的依賴項(xiàng),這種方式就很實(shí)用。

不過(guò)有一點(diǎn)要注意的是:go run的退出狀態(tài)并不等于編譯后二進(jìn)制文件的退出狀態(tài),看下面這個(gè)示例:

// main.go成功退出
$go run main.go
Hello from myapp!
$echo $?        
0

// main.go中調(diào)用os.Exit(2)退出
$go run main.go               
Hello from myapp!
exit status 2
$echo $?        
1

go run使用退出狀態(tài)1來(lái)表示其運(yùn)行程序的異常退出狀態(tài),但這個(gè)值和真實(shí)的exit的狀態(tài)值不相等。

到這里我們看到,go run xxx.go可以像bash xxx.sh或python xxx.py那樣,以“解釋”方式運(yùn)行一個(gè)Go源碼文件。這使得Go語(yǔ)言在某種程度上具備了腳本語(yǔ)言的特性。然而,在腳本語(yǔ)言中,例如Bash或Python等,用戶可以通過(guò)將源碼文件設(shè)置為可執(zhí)行,并在文件的首行添加適當(dāng)?shù)慕忉屍髦噶睿瑥亩苯舆\(yùn)行腳本,而無(wú)需顯式調(diào)用解釋器。這種靈活性使得腳本的執(zhí)行變得更加簡(jiǎn)便。那么Go是否也可以做到這一點(diǎn)呢?我們繼續(xù)往下看。

4. Go腳本化的實(shí)現(xiàn)方式

下面是通過(guò)一些技巧或第三方工具實(shí)現(xiàn)Go腳本化的方法。對(duì)于喜歡使用腳本的人來(lái)說(shuō),最熟悉的莫過(guò)于shebang(即解釋器指令)。在許多腳本語(yǔ)言中,通過(guò)在文件的第一行添加指定的解釋器路徑,可以直接運(yùn)行腳本,而無(wú)需顯式調(diào)用解釋器。例如,在Bash或Python腳本中,通常會(huì)看到這樣的行:

#!/usr/bin/env python3

那么Go語(yǔ)言支持shebang嗎? 是否可以實(shí)現(xiàn)實(shí)現(xiàn)類似的效果呢?我們下面來(lái)看看。

4.1 使用“shebang(#!)”運(yùn)行Go腳本

很遺憾,Go不能直接支持shebang,我們看一下這個(gè)示例main.go:

#!/usr/bin/env go run 

package main

import (
 "fmt"
 "os"
)

func main() {
 s := "world"
 if len(os.Args) > 1 {
  s = os.Args[1]
 }
 fmt.Printf("Hello, %v!\n", s)
}

這一示例的第一行就是一個(gè)shebang解釋器指令,我們chmod u+x main.go,然后執(zhí)行該Go“腳本”:

$./main.go
main.go:1:1: illegal character U+0023 '#'

這個(gè)執(zhí)行過(guò)程中,Shell可以正常識(shí)別shebang,然后調(diào)用go run去運(yùn)行main.go,問(wèn)題就在于go編譯器視shebang這一行為非法語(yǔ)法!

常規(guī)的shebang寫法行不通,我們就使用一些trick,下面是改進(jìn)后的示例:

//usr/bin/env go run $0 $@; exit

package main

import (
 "fmt"
 "os"
)

func main() {
 s := "world"
 if len(os.Args) > 1 {
  s = os.Args[1]
 }
 fmt.Printf("Hello, %v!\n", s)
}

這段代碼則可以chmod +x 后直接運(yùn)行:

$./main.go     
Hello, world!
$./main.go gopher
Hello, gopher!

這是因?yàn)樗擅畹亟Y(jié)合了shell腳本和Go代碼的特性。我們來(lái)看一下第一行:

//usr/bin/env go run $0 $@; exit

這一行看起來(lái)像是Go的注釋,但實(shí)際上是一個(gè)shell命令。當(dāng)文件被執(zhí)行時(shí),shell會(huì)解釋這一行,/usr/bin/env用于尋找go命令的路徑,go run @ 告訴go命令運(yùn)行當(dāng)前腳本文件(以及所有傳遞給腳本的參數(shù)@),當(dāng)go run編譯這個(gè)腳本時(shí),又會(huì)將第一行當(dāng)做注釋行而忽略,這就是關(guān)鍵所在。最后的exit確保shell在Go程序執(zhí)行完畢后退出。如果沒(méi)有exit,shell會(huì)執(zhí)行后續(xù)Go代碼,那顯然會(huì)導(dǎo)致報(bào)錯(cuò)!

除了上述trick外,我們還可以將Go源碼文件注冊(cè)為可執(zhí)行格式(僅在linux上進(jìn)行了測(cè)試),下面就是具體操作步驟。

4.2 在Linux系統(tǒng)中注冊(cè)Go為可執(zhí)行格式

就像在Windows上雙擊某個(gè)文件后,系統(tǒng)打開(kāi)特定程序處理對(duì)應(yīng)的文件一樣,我們也可以將Go源文件(xxx.go)注冊(cè)為可執(zhí)行格式,并指定用于處理該文件的程序。實(shí)現(xiàn)這一功能,我們需要借助binfmt_misc。binfmt_misc是Linux內(nèi)核的一個(gè)功能,允許用戶注冊(cè)新的可執(zhí)行文件格式。這使得Linux系統(tǒng)能夠識(shí)別并執(zhí)行不同類型的可執(zhí)行文件,比如腳本、二進(jìn)制文件等。

我們用下面命令將Go源文件注冊(cè)到binfmt_misc中:

echo ':golang:E::go::/usr/local/bin/gorun:OC' | sudo tee /proc/sys/fs/binfmt_misc/register

簡(jiǎn)單解釋一下上述命令:

  • :golang::這是注冊(cè)的格式的名稱,可以自定義。
  • E:::表示執(zhí)行文件的魔數(shù)(magic number),在這里為空,表示任何文件類型。
  • go:::指定用于執(zhí)行的解釋器,這里是go命令。
  • /usr/local/bin/gorun:指定用于執(zhí)行的程序路徑,這里是一個(gè)自定義的gorun腳本
  • :OC:表示這個(gè)格式是可執(zhí)行的(O)并且支持在運(yùn)行時(shí)創(chuàng)建(C)。

當(dāng)你執(zhí)行一個(gè)Go源文件時(shí),Linux內(nèi)核會(huì)檢查文件的類型。如果文件的格式與注冊(cè)的格式匹配,內(nèi)核會(huì)調(diào)用指定的解釋器(在這個(gè)例子中是gorun)來(lái)執(zhí)行該文件。

gorun腳本是我們自己編寫的,源碼如下:

#!/bin/bash

# 檢查是否提供了源文件
if [ -z "$1" ]; then
  echo "用法: gorun <go源文件> [參數(shù)...]"
  exit 1
fi

# 檢查文件是否存在
if [ ! -f "$1" ]; then
  echo "錯(cuò)誤: 文件 $1 不存在"
  exit 1
fi

# 將第一個(gè)參數(shù)作為源文件,剩余的參數(shù)作為執(zhí)行參數(shù)
GO_FILE="$1"
shift  # 移除第一個(gè)參數(shù),剩余的參數(shù)將會(huì)被傳遞

# 使用go run命令執(zhí)行Go源文件,傳遞其余參數(shù)
go run "$GO_FILE" "$@"

將gorun腳本放置帶/usr/local/bin下,并chmod +x使其具有可執(zhí)行權(quán)限。

接下來(lái),我們就可以直接執(zhí)行不帶有"shebang"的正常go源碼了:

// main.go
package main

import (
    "fmt"
    "os"
)
  
func main() {
      s := "world"
      if len(os.Args) > 1 {
          s = os.Args[1]
      }
      fmt.Printf("Hello, %v!\n", s)
}

直接執(zhí)行上述源文件:

$ ./main.go
Hello, world!
$ ./main.go gopher
Hello, gopher!

4.3 第三方工具支持

Go社區(qū)也有一些將支持將Go源文件視為腳本的解釋器工具,比如:traefik/yaegi[6]等。

$go install github.com/traefik/yaegi/cmd/yaegi@latest
go: downloading github.com/traefik/yaegi v0.16.1
$yaegi main.go
Hello, main.go!

yaegi還可以像python那樣,提供Read-Eval-Print-Loop功能,我們可以與yaegi配合進(jìn)行交互式“Go腳本”編碼:

$ yaegi
> 1+2
: 3
> import "fmt"
: 0xc0003900d0
> fmt.Println("hello, golang")
hello, golang
: 14
>

類似的提供REPL功能的第三方Go解釋器還包括:cosmos72/gomacro[7]、x-motemen/gore[8]等,這里就不深入介紹了,感興趣的童鞋可以自行研究。

5. 小結(jié)

在本文中,我們探討了Go語(yǔ)言在DevOps和日常腳本編寫中的多面性。首先,Go語(yǔ)言因其高性能、并發(fā)處理能力及跨平臺(tái)編譯特性,成為DevOps領(lǐng)域的重要工具,助力于自動(dòng)化任務(wù)和微服務(wù)部署。其次,隨著Go語(yǔ)言的普及,其作為腳本語(yǔ)言的潛力逐漸被開(kāi)發(fā)運(yùn)維人員認(rèn)識(shí),Go展現(xiàn)出了優(yōu)于傳統(tǒng)腳本語(yǔ)言的高效性和可靠性。

我們還介紹了Go腳本的實(shí)現(xiàn)方式,包括使用go run命令,它使得Go程序的執(zhí)行更像傳統(tǒng)腳本語(yǔ)言,同時(shí)也探討了一些技巧和工具,幫助開(kāi)發(fā)者將Go源碼文件作為可執(zhí)行腳本直接運(yùn)行。通過(guò)這些探索,我們可以看到Go語(yǔ)言在現(xiàn)代開(kāi)發(fā)中的靈活應(yīng)用及其日益增長(zhǎng)的吸引力。

隨著AI能力的飛速發(fā)展,使用Go編寫一個(gè)日常腳本就是分分鐘的事情,但Go的特性讓這樣的腳本具備了傳統(tǒng)腳本語(yǔ)言所不具備的并發(fā)性、可靠性和性能優(yōu)勢(shì)。我們有理由相信,Go在DevOps和腳本編程領(lǐng)域的應(yīng)用將會(huì)越來(lái)越廣泛,為開(kāi)發(fā)者帶來(lái)更多的可能性和便利。

6. 參考資料

  • Using Go as a scripting language in Linux[9] - https://blog.cloudflare.com/using-go-as-a-scripting-language-in-linux/
  • Go as a Scripting Language[10] - https://www.infoq.com/news/2020/04/go-scripting-language/
  • Go compared to Python for small scale system administration scripts and tools[11] - https://utcc.utoronto.ca/~cks/space/blog/sysadmin/SysadminGoVsPython

參考資料

[1] Reddit Go論壇: https://www.reddit.com/r/golang/

[2] Rust: https://tonybai.com/tag/rust

[3] 為何Go是DevOps語(yǔ)言: https://www.reddit.com/r/golang/comments/1fqwbv0/why_is_golang_the_language_of_devops/

[4] Go適合用作腳本語(yǔ)言嗎: https://www.reddit.com/r/golang/comments/1ftpk2m/do_you_use_go_for_scripts/

[5] 平臺(tái)工程(Platform Engineering): https://en.wikipedia.org/wiki/Platform_engineering

[6] traefik/yaegi: https://github.com/traefik/yaegi

[7] cosmos72/gomacro: https://github.com/cosmos72/gomacro

[8] x-motemen/gore: https://github.com/x-motemen/gore

[9] Using Go as a scripting language in Linux: https://blog.cloudflare.com/using-go-as-a-scripting-language-in-linux/

[10] Go as a Scripting Language: https://www.infoq.com/news/2020/04/go-scripting-language/

[11] Go compared to Python for small scale system administration scripts and tools: https://utcc.utoronto.ca/~cks/space/blog/sysadmin/SysadminGoVsPython

責(zé)任編輯:武曉燕 來(lái)源: TonyBai
相關(guān)推薦

2023-12-27 06:48:49

KubernetesDevOpsHTTP

2021-04-29 09:02:44

語(yǔ)言Go 處理

2021-03-28 20:58:25

Go語(yǔ)言線程

2023-03-21 07:57:37

Go語(yǔ)言設(shè)計(jì)模式

2021-07-13 06:44:04

Go語(yǔ)言數(shù)組

2023-12-20 14:44:33

軟件開(kāi)發(fā)DevOpsNoOps

2017-12-27 14:52:21

JSGo編程語(yǔ)言

2021-09-01 22:58:22

Canvas標(biāo)簽

2022-06-22 09:24:30

云原生Go 語(yǔ)言

2023-01-31 08:48:49

Go語(yǔ)言文件

2022-11-01 12:16:47

Nginx微服務(wù)編譯

2024-08-28 10:36:19

2019-12-24 08:29:25

DevOpsDevSecOps工具

2024-02-21 23:16:08

C語(yǔ)言開(kāi)發(fā)

2018-10-10 14:02:30

Linux系統(tǒng)硬件內(nèi)核

2020-05-08 11:42:24

JavaScript編程語(yǔ)言技術(shù)

2017-03-13 09:19:38

CAP編程語(yǔ)言

2024-04-26 08:17:09

GoGoogle項(xiàng)目

2018-05-31 15:27:59

DevOpsDataOps數(shù)據(jù)中心

2021-01-06 09:47:51

內(nèi)存Go語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)