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

Go語(yǔ)言的9大優(yōu)勢(shì)和3大缺點(diǎn)

開發(fā) 后端
轉(zhuǎn)用一門新語(yǔ)言通常是一項(xiàng)大決策,尤其是當(dāng)你的團(tuán)隊(duì)成員中只有一個(gè)使用過它時(shí)。今年 Stream 團(tuán)隊(duì)的主要編程語(yǔ)言從 Python 轉(zhuǎn)向了 Go。本文解釋了其背后的九大原因以及如何做好這一轉(zhuǎn)換。

轉(zhuǎn)用一門新語(yǔ)言通常是一項(xiàng)大決策,尤其是當(dāng)你的團(tuán)隊(duì)成員中只有一個(gè)使用過它時(shí)。今年 Stream 團(tuán)隊(duì)的主要編程語(yǔ)言從 Python 轉(zhuǎn)向了 Go。本文解釋了其背后的九大原因以及如何做好這一轉(zhuǎn)換。

Go的優(yōu)勢(shì)

原因 1:性能

[[207384]]

Go 極其地快。其性能與 Java 或 C++相似。在我們的使用中,Go 一般比 Python 要快 30 倍。以下是 Go 與 Java 之間的基準(zhǔn)比較:

Go語(yǔ)言的9大優(yōu)勢(shì)和3大缺點(diǎn)

Go語(yǔ)言的9大優(yōu)勢(shì)和3大缺點(diǎn)

Go語(yǔ)言的9大優(yōu)勢(shì)和3大缺點(diǎn)

Go語(yǔ)言的9大優(yōu)勢(shì)和3大缺點(diǎn)

原因 2:語(yǔ)言性能很重要

對(duì)很多應(yīng)用來(lái)說,編程語(yǔ)言只是簡(jiǎn)單充當(dāng)了其與數(shù)據(jù)集之間的膠水。語(yǔ)言本身的性能常常無(wú)關(guān)輕重。

但是 Stream 是一個(gè) API 提供商,服務(wù)于世界 500 強(qiáng)以及超過 2 億的終端用戶。數(shù)年來(lái)我們已經(jīng)優(yōu)化了 Cassandra、PostgreSQL、Redis 等等,然而最終抵達(dá)了所使用語(yǔ)言的極限。

Python 非常棒,但是其在序列化/去序列化、排序和聚合中表現(xiàn)欠佳。我們經(jīng)常會(huì)遇到這樣的問題:Cassandra 用時(shí) 1ms 檢索了數(shù)據(jù),Python 卻需要 10ms 將其轉(zhuǎn)化成對(duì)象。

原因 3:開發(fā)者效率&不要過于創(chuàng)新

看一下***的入門教程《開始學(xué)習(xí) Go 語(yǔ)言》(http://howistart.org/posts/go/1/)中的一小段代碼:

 

  1. package main 
  2. type openWeatherMap struct{}func (w openWeatherMap) temperature(city string) (float64, error) { 
  3.    resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?APPID=YOUR_API_KEY&q=" + city) 
  4.    if err != nil { 
  5.        return 0, err 
  6.    } 
  7.    defer resp.Body.Close() 
  8.    var d struct { 
  9.        Main struct { 
  10.            Kelvin float64 `json:"temp"
  11.        } `json:"main"
  12.    } 
  13.    if err := json.NewDecoder(resp.Body).Decode(&d); err != nil { 
  14.        return 0, err 
  15.    } 
  16.    log.Printf("openWeatherMap: %s: %.2f", city, d.Main.Kelvin) 
  17.    return d.Main.Kelvin, nil} 

如果你是一個(gè)新手,看到這段代碼你并不會(huì)感到吃驚。它展示了多種賦值、數(shù)據(jù)結(jié)構(gòu)、指針、格式化以及內(nèi)置的 HTTP 庫(kù)。

當(dāng)我***次編程時(shí),我很喜歡使用 Python 的高階功能。Python 允許你創(chuàng)造性地使用正在編寫的代碼,比如,你可以:

  • 在代碼初始化時(shí),使用 MetaClasses 自行注冊(cè)類別
  • 置換真假
  • 添加函數(shù)到內(nèi)置函數(shù)列表中
  • 通過奇妙的方法重載運(yùn)算符

毋庸置疑這些代碼很有趣,但也使得在讀取其他人的工作時(shí),代碼變得難以理解。

Go 強(qiáng)迫你堅(jiān)持打牢基礎(chǔ),這也就為讀取任意代碼帶來(lái)了便利,并能很快搞明白當(dāng)下發(fā)生的事情。

注意:當(dāng)然如何容易還是要取決于你的使用案例。如果你要?jiǎng)?chuàng)建一個(gè)基本的 CRUD API,我還是建議你使用 Django + DRF,或者 Rails。

原因 4:并發(fā)性&通道

Go 作為一門語(yǔ)言致力于使事情簡(jiǎn)單化。它并未引入很多新概念,而是聚焦于打造一門簡(jiǎn)單的語(yǔ)言,它使用起來(lái)異常快速并且簡(jiǎn)單。其唯一的創(chuàng)新之處是 goroutines 和通道。Goroutines 是 Go 面向線程的輕量級(jí)方法,而通道是 goroutines 之間通信的優(yōu)先方式。

創(chuàng)建 Goroutines 的成本很低,只需幾千個(gè)字節(jié)的額外內(nèi)存,正由于此,才使得同時(shí)運(yùn)行數(shù)百個(gè)甚至數(shù)千個(gè) goroutines 成為可能。你可以借助通道實(shí)現(xiàn) goroutines 之間的通信。Go 運(yùn)行時(shí)間可以表示所有的復(fù)雜性。Goroutines 以及基于通道的并發(fā)性方法使其非常容易使用所有可用的 CPU 內(nèi)核,并處理并發(fā)的 IO——所有不帶有復(fù)雜的開發(fā)。相較于 Python/Java,在一個(gè) goroutine 上運(yùn)行一個(gè)函數(shù)需要最小的樣板代碼。你只需使用關(guān)鍵詞「go」添加函數(shù)調(diào)用:

 

  1. package main 
  2. import ( 
  3.    "fmt" 
  4.    "time")func say(s string) { 
  5.    for i := 0; i < 5; i++ { 
  6.        time.Sleep(100 * time.Millisecond) 
  7.        fmt.Println(s) 
  8.    }}func main() { 
  9.    go say("world"
  10.    say("hello")} 

Go 的并發(fā)性方法非常容易上手,相較于 Node 也很有趣;在 Node 中,開發(fā)者必須密切關(guān)注異步代碼的處理。

并發(fā)性的另一個(gè)優(yōu)質(zhì)特性是競(jìng)賽檢測(cè)器,這使其很容易弄清楚異步代碼中是否存在競(jìng)態(tài)條件。下面是一些上手 Go 和通道的很好的資源:

  • https://gobyexample.com/channels
  • https://tour.golang.org/concurrency/2
  • http://guzalexander.com/2013/12/06/golang-channels-tutorial.html
  • https://www.golang-book.com/books/intro/10
  • https://www.goinggo.net/2014/02/the-nature-of-channels-in-go.html

原因 5:快速的編譯時(shí)間

當(dāng)前我們使用 Go 編寫的***微服務(wù)的編譯時(shí)間只需 6 秒。相較于 Java 和 C++呆滯的編譯速度,Go 的快速編譯時(shí)間是一個(gè)主要的效率優(yōu)勢(shì)。我熱愛擊劍,但是當(dāng)我依然記得代碼應(yīng)該做什么之時(shí),事情已經(jīng)完成就更好了。

Go語(yǔ)言的9大優(yōu)勢(shì)和3大缺點(diǎn)

Go 之前的代碼編譯

原因 6:打造團(tuán)隊(duì)的能力

首先,最明顯的一點(diǎn)是:Go 的開發(fā)者遠(yuǎn)沒有 C++和 Java 等舊語(yǔ)言多。據(jù)知,有 38% 的開發(fā)者了解 Java,19.3% 的開發(fā)者了解 C++,只有 4.6% 的開發(fā)者知道 Go。GitHub 數(shù)據(jù)表明了相似的趨勢(shì):相較于 Erlang、Scala 和 Elixir,Go 更為流行,但是相較于 Java 和 C++ 就不是了。

幸運(yùn)的是 Go 非常簡(jiǎn)單,且易于學(xué)習(xí)。它只提供了基本功能而沒有多余。Go 引入的新概念是「defer」聲明,以及內(nèi)置的帶有 goroutines 和通道的并發(fā)性管理。正是由于 Go 的簡(jiǎn)單性,任何的 Python、Elixir、C++、Scala 或者 Java 開發(fā)者皆可在一月內(nèi)組建成一個(gè)高效的 Go 團(tuán)隊(duì)。

原因 7:強(qiáng)大的生態(tài)系統(tǒng)

對(duì)我們這么大小的團(tuán)隊(duì)(大約 20 人)而言,生態(tài)系統(tǒng)很重要。如果你需要重做每塊功能,那就無(wú)法為客戶創(chuàng)造收益了。Go 有著強(qiáng)大的工具支持,面向 Redis、RabbitMQ、PostgreSQL、Template parsing、Task scheduling、Expression parsing 和 RocksDB 的穩(wěn)定的庫(kù)。

Go 的生態(tài)系統(tǒng)相比于 Rust、Elixir 這樣的語(yǔ)言有很大的優(yōu)勢(shì)。當(dāng)然,它又略遜于 Java、Python 或 Node 這樣的語(yǔ)言,但它很穩(wěn)定,而且你會(huì)發(fā)現(xiàn)在很多基礎(chǔ)需求上,已經(jīng)有高質(zhì)量的文件包可用了。

原因 8:GOFMT,強(qiáng)制代碼格式

Gofmt 是一種強(qiáng)大的命令行功能,內(nèi)建在 Go 的編譯器中來(lái)規(guī)定代碼的格式。從功能上看,它類似于 Python 的 autopep8。格式一致很重要,但實(shí)際的格式標(biāo)準(zhǔn)并不總是非常重要。Gofmt 用一種官方的形式規(guī)格代碼,避免了不必要的討論。

原因 9:gRPC 和 Protocol Buffers

Go 語(yǔ)言對(duì) protocol buffers 和 gRPC 有***的支持。這兩個(gè)工具能一起友好地工作以構(gòu)建需要通過 RPC 進(jìn)行通信的微服務(wù)器(microservices)。我們只需要寫一個(gè)清單(manifest)就能定義 RPC 調(diào)用發(fā)生的情況和參數(shù),然后從該清單將自動(dòng)生成服務(wù)器和客戶端代碼。這樣產(chǎn)生代碼不僅快速,同時(shí)網(wǎng)絡(luò)占用也非常少。

從相同的清單,我們可以從不同的語(yǔ)言生成客戶端代碼,例如 C++、Java、Python 和 Ruby。因此內(nèi)部通信的 RESET 端點(diǎn)不會(huì)產(chǎn)生分歧,我們每次也就需要編寫幾乎相同的客戶端和服務(wù)器代碼。

使用 Go 語(yǔ)言的缺點(diǎn)

缺點(diǎn) 1:缺少框架

Go 語(yǔ)言沒有一個(gè)主要的框架,如 Ruby 的 Rails 框架、Python 的 Django 框架或 PHP 的 Laravel。這是 Go 語(yǔ)言社區(qū)激烈討論的問題,因?yàn)樵S多人認(rèn)為我們不應(yīng)該從使用框架開始。在很多案例情況中確實(shí)如此,但如果只是希望構(gòu)建一個(gè)簡(jiǎn)單的 CRUD API,那么使用 Django/DJRF、Rails Laravel 或 Phoenix 將簡(jiǎn)單地多。

缺點(diǎn) 2:錯(cuò)誤處理

Go 語(yǔ)言通過函數(shù)和預(yù)期的調(diào)用代碼簡(jiǎn)單地返回錯(cuò)誤(或返回調(diào)用堆棧)而幫助開發(fā)者處理編譯報(bào)錯(cuò)。雖然這種方法是有效的,但很容易丟失錯(cuò)誤發(fā)生的范圍,因此我們也很難向用戶提供有意義的錯(cuò)誤信息。錯(cuò)誤包(errors package)可以允許我們添加返回錯(cuò)誤的上下文和堆棧追蹤而解決該問題。

另一個(gè)問題是我們可能會(huì)忘記處理報(bào)錯(cuò)。諸如 errcheck 和 megacheck 等靜態(tài)分析工具可以避免出現(xiàn)這些失誤。雖然這些解決方案十分有效,但可能并不是那么正確的方法。

缺點(diǎn) 3:軟件包管理

Go 語(yǔ)言的軟件包管理絕對(duì)不是***的。默認(rèn)情況下,它沒有辦法制定特定版本的依賴庫(kù),也無(wú)法創(chuàng)建可復(fù)寫的 builds。相比之下 Python、Node 和 Ruby 都有更好的軟件包管理系統(tǒng)。然而通過正確的工具,Go 語(yǔ)言的軟件包管理也可以表現(xiàn)得不錯(cuò)。

我們可以使用 Dep 來(lái)管理依賴項(xiàng),它也能指定特定的軟件包版本。除此之外,我們還可以使用一個(gè)名為 VirtualGo 的開源工具,它能輕松地管理 Go 語(yǔ)言編寫的多個(gè)項(xiàng)目。

 

[[207385]]

Python vs Go

我們實(shí)施的一個(gè)有趣實(shí)驗(yàn)是用 Python 寫排名 feed,然后用 Go 改寫??聪旅孢@種排序方法的示例:

 

  1.    "functions": { 
  2.        "simple_gauss": { 
  3.            "base""decay_gauss"
  4.            "scale""5d"
  5.            "offset""1d"
  6.            "decay""0.3" 
  7.        }, 
  8.        "popularity_gauss": { 
  9.            "base""decay_gauss"
  10.            "scale""100"
  11.            "offset""5"
  12.            "decay""0.5" 
  13.        } 
  14.    }, 
  15.    "defaults": { 
  16.        "popularity": 1 
  17.    }, 
  18.    "score""simple_gauss(time)*popularity"

Python 和 Go 代碼都需要以下要求從而支持上面的排序方法:

  • 解析得分的表達(dá)。在此示例中,我們想要把 simple_gauss(time)*popularity 字符串轉(zhuǎn)變?yōu)橐环N函數(shù),能夠把 activity 作為輸入然后給出得分作為輸出。
  • 在 JSON config 上創(chuàng)建部分函數(shù)。例如,我們想要「simple_gauss」調(diào)用「decay_gauss」,且?guī)в械逆I值對(duì)為”scale”: “5d”、”offset”: “1d”、”decay”: “0.3”。
  • 解析「defaults」配置,便于某個(gè)領(lǐng)域沒有明確定義的情況下有所反饋。
  • 從 step1 開始使用函數(shù),為 feed 中的所有 activity 打分。

開發(fā) Python 版本排序代碼大約需要 3 天,包括寫代碼、測(cè)試和建立文檔。接下來(lái),我么花費(fèi)大約 2 周的時(shí)間優(yōu)化代碼。其中一個(gè)優(yōu)化是把得分表達(dá) simple_gauss(time)*popularity 轉(zhuǎn)譯進(jìn)一個(gè)抽象語(yǔ)法樹。我們也實(shí)現(xiàn)了 caching logic,之后會(huì)預(yù)先計(jì)算每次的得分。

相比之下,開發(fā) Go 版本的代碼需要 4 天,但之后不需要更多的優(yōu)化。所以雖然最初的開發(fā)上 Python 更快,但 Go 最終需要的工作量更少。此外,Go 代碼要比高度優(yōu)化的 python 代碼快了 40 多倍。

以上只是我們轉(zhuǎn)向 Go 所體驗(yàn)到的一種好處。當(dāng)然,也不能這么做比較:

  • 該排序代碼是我用 Go 寫的***個(gè)項(xiàng)目;
  • Go 代碼是在 Python 代碼之后寫的,所以提前理解了該案例;
  • Go 的表達(dá)解析庫(kù)質(zhì)量?jī)?yōu)越。

Elixir vs Go

我們?cè)u(píng)估的另一種語(yǔ)言是 Elixir。Elixir 建立在 Erlang 虛擬機(jī)上。這是一種迷人的語(yǔ)言,我們之所以想到它是因?yàn)槲覀兘M員中有一個(gè)在 Erlang 上非常有經(jīng)驗(yàn)。

在使用案例中,我們觀察到 Go 的原始性能更好。Go 和 Elixir 都能很好地處理數(shù)千條并行需求,然而,如果是單獨(dú)的要求,Go 實(shí)際上更快。相對(duì)于 Elixir,我們選擇 Go 的另一個(gè)原因是生態(tài)系統(tǒng)。在我們需求的組件上,Go 的庫(kù)更為成熟。在很多案例中,Elixir 庫(kù)不適合產(chǎn)品使用。同時(shí),也很難找到/訓(xùn)練同樣使用 Elixir 的開發(fā)者。

結(jié)論

Go 是一種非常高效的語(yǔ)言,高度支持并發(fā)性。同時(shí),它也像 C++和 Java 一樣快。雖然相比于 Python 和 Ruby,使用 Go 建立東西需要更多的時(shí)間,但在后續(xù)的代碼優(yōu)化上可以節(jié)省大量時(shí)間。在 Stream,我們有個(gè)小型開發(fā)團(tuán)隊(duì)為 2 億終端用戶提供 feed 流。對(duì)新手開發(fā)者而言,Go 結(jié)合了強(qiáng)大的生態(tài)系統(tǒng)、易于上手,也有超快的表現(xiàn)、高度支持并發(fā)性,富有成效的編程環(huán)境使它成為了一種好的選擇。Stream 仍舊使用 Python 做個(gè)性化 feed,但所有性能密集型的代碼將會(huì)用 Go 來(lái)編寫。

責(zé)任編輯:未麗燕 來(lái)源: 機(jī)器之心譯
相關(guān)推薦

2009-04-08 10:34:00

IPSec VPN協(xié)議

2021-09-27 10:37:36

人工智能AI深度學(xué)習(xí)

2018-08-14 11:05:25

2009-06-19 18:10:38

Hibernate

2010-12-14 08:35:13

編程語(yǔ)言

2017-10-18 15:37:13

PythonGo語(yǔ)言Java

2024-06-06 09:47:56

2021-07-26 05:38:53

IaC基礎(chǔ)設(shè)施即代碼開發(fā)

2020-08-30 16:27:30

多云云計(jì)算

2025-03-24 00:25:00

Go語(yǔ)言并發(fā)編程

2010-04-13 15:45:49

2009-06-22 14:07:46

JSF優(yōu)勢(shì)

2009-06-01 11:51:37

hibernate緩存機(jī)制開發(fā)者

2024-03-14 15:11:54

2017-07-31 10:31:13

2022-01-10 23:30:18

云計(jì)算開發(fā)數(shù)據(jù)

2020-10-10 10:24:53

5G

2019-01-22 15:32:05

Go語(yǔ)言工具開發(fā)

2019-04-26 09:37:30

Go 開源技術(shù)

2018-08-30 07:33:23

物聯(lián)網(wǎng)卡運(yùn)營(yíng)商物聯(lián)網(wǎng)
點(diǎn)贊
收藏

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