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

為什么要用Go語言?

開發(fā) 后端
本文從Go語言被設(shè)計的初衷出發(fā),深入互聯(lián)網(wǎng)各種角落,調(diào)查Go所具有的那些特性是否足夠優(yōu)秀,同時和其他語言進(jìn)行適當(dāng)?shù)谋容^,你可以選擇性的閱讀、接受或者反對我的內(nèi)容,畢竟有交流才能傳播知識。

前言

Go 是一個開源的編程語言,它能讓構(gòu)造簡單、可靠且高效的軟件變得容易[1]。

Go 語言被設(shè)計成一門應(yīng)用于搭載 Web 服務(wù)器,存儲集群或類似用途的巨型中央服務(wù)器的系統(tǒng)編程語言。對于高性能分布式系統(tǒng)領(lǐng)域而言,Go語言無疑比大多數(shù)其它語言有著更高的開發(fā)效率。它提供了海量并行的支持,這對于游戲服務(wù)端的開發(fā)而言是再好不過了[1]。

其實早在2018年前,我就已經(jīng)有在國內(nèi)的程序員環(huán)境中斷斷續(xù)續(xù)地聽到Go語言的消息,Go語言提供的方便的并發(fā)編程方式,十分適合我當(dāng)時選擇的畢業(yè)設(shè)計選題,但是受限于導(dǎo)師的語言選擇、項目的進(jìn)度追趕、考研的時間壓榨,一直沒有機(jī)會來好好地學(xué)習(xí)這門語言。

[[321335]]

在進(jìn)入研究生階段后,盡管研究的方向和算法相關(guān),但未來的職業(yè)方向還是選擇了以后端為主,主要是因為想做更多和業(yè)務(wù)相關(guān)的工作。為了能在有限的時間里給予自己足夠深的知識底蘊,選擇了一些讓自己去深入了解的方向,Go語言自然也在其中,今天終于有機(jī)會來開始研究這門語言。

為什么要用Go語言?

撰寫此文的初衷,是本文的標(biāo)題,也是我作為初學(xué)者一直以來的疑問:

“我為什么要用Go語言?”

為了回答這個問題,我翻閱了很多Go語言相關(guān)的文檔、書籍和教程,我發(fā)現(xiàn)我很難在它們之中找到非常明顯直接的答案,書上和教程只會說,“是的,Go語言好用”。

對于部分人來說,這個問題的答案或許很“明顯”,比如選擇Go語言是因為Google設(shè)計的語言、Go開發(fā)賺的錢多、XX公司使用Go語言等等,如果想要了解這門語言更加本質(zhì)的東西,僅僅這些答案我認(rèn)為是還不夠的。

部分Go的教徒可能會說,他們選擇的理由是和語言本身相關(guān)的,比如:

  • Go編譯快
  • Go執(zhí)行快
  • Go并發(fā)編程方便
  • Go有垃圾回收(Garbage Collection, GC)

的確,Go是有這些特點,但這并非都是Go獨有的:

  • 運行時解釋的腳本語言(比如Python)幾乎不需要時間編譯
  • C、C++甚至是匯編,基本上能夠榨干一臺機(jī)器的大部分性能
  • 大部分語言都有并發(fā)編程的支持庫
  • 大部分語言都不需要程序員主動關(guān)注內(nèi)存情況

一些Go的忠實粉絲把這種All in One的特性作為評價語言的標(biāo)準(zhǔn),他們認(rèn)為至少在這些方面,Go是可以完美的代替其他語言的。

那么,Go真的能優(yōu)秀到完全替代另一個語言么?

其實未必,我始終認(rèn)為銀彈是不存在的[2],無論是在這次調(diào)查前,還是在這次調(diào)查后。

本文從Go語言被設(shè)計的初衷出發(fā),深入互聯(lián)網(wǎng)各種角落,調(diào)查Go所具有的那些特性是否足夠優(yōu)秀,同時和其他語言進(jìn)行適當(dāng)?shù)谋容^,你可以選擇性的閱讀、接受或者反對我的內(nèi)容,畢竟有交流才能傳播知識。

我的最終目的是讓更多的初學(xué)者看到Go沒有輕易暴露出的缺點,同時也能看到Go真正優(yōu)秀的地方。

設(shè)計Go的初衷

Go語言的主要目標(biāo)是將靜態(tài)語言的安全性和高效性與動態(tài)語言的易開發(fā)性進(jìn)行有機(jī)結(jié)合,達(dá)到完美平衡,從而使編程變得更加有樂趣,而不是在艱難抉擇中痛苦前行[3]。

Google公司不可能無緣無故地設(shè)計一個新語言(一些特性相比于其他語言也沒有新到哪里去),這一切肯定是有原因的。

設(shè)計Go語言是為了解決當(dāng)時Google開發(fā)遇到的一些問題[4]:

  • C++編譯慢、沒有現(xiàn)代化(入門級友好的)的內(nèi)存管理
  • 數(shù)以萬計行的代碼,難以維護(hù)
  • 部署的平臺各式各樣,交叉編譯困難
  • ......

 

找不到什么合適的語言,想著反正都是弄來自己用,Google選擇造個輪子試試。

Go 語言起源 2007 年,并于 2009 年正式對外發(fā)布。它從 2009 年 9 月 21 日開始作為谷歌公司 20%兼職項目,即相關(guān)員工利用 20% 的空余時間來參與 Go 語言的研發(fā)工作。該項目的三位領(lǐng)導(dǎo)者均是著名的 IT 工程師:Robert Griesemer,參與開發(fā) Java HotSpot 虛擬機(jī);Rob Pike,Go 語言項目總負(fù)責(zé)人,貝爾實驗室 Unix 團(tuán)隊成員,參與的項目包括 Plan 9,Inferno 操作系統(tǒng)和 Limbo 編程語言;Ken Thompson,貝爾實驗室 Unix 團(tuán)隊成員,C 語言、Unix 和 Plan 9 的創(chuàng)始人之一,與 Rob Pike 共同開發(fā)了 UTF-8 字符集規(guī)范。自 2008 年 1 月起,Ken Thompson 就開始研發(fā)一款以 C 語言為目標(biāo)結(jié)果的編譯器來拓展 Go 語言的設(shè)計思想[3]。

當(dāng)時Google的很多工程師是用的都是C/C++,所以語法的設(shè)計上接近于C,Go的設(shè)計師們想要解決其他語言使用中的缺點,但是仍保留他們的優(yōu)點[5]:

  • 靜態(tài)類型和運行時效率
  • 可讀性和易用性
  • 高性能的網(wǎng)絡(luò)和多進(jìn)程
  • ...

emmm,這些聽起來還是比較玄乎,畢竟設(shè)計歸設(shè)計,實現(xiàn)歸實現(xiàn),我們回顧一下現(xiàn)在Go的幾個主要特點,編譯速度、執(zhí)行速度、內(nèi)存管理以及并發(fā)編程。

Go的編譯為什么快

當(dāng)然,設(shè)計Go語言也不是完全從零開始,最初Go的團(tuán)隊嘗試設(shè)計實現(xiàn)一個Go語言的編譯前端,由基于C的gcc編譯器來編譯成機(jī)器代碼,這個面向gcc的前端編譯器也就是目前的Go編譯器之一的gccgo。

與其說Go的編譯為什么快,不如先說說C++的編譯為什么慢,C++也可以用gcc編譯,編譯速度的大部分差異很有可能來源于語言設(shè)計本身。

在討論問題之前,其中需要先說明的一點是:這里比較的編譯速度都是在靜態(tài)編譯下的。

靜態(tài)編譯和動態(tài)編譯的區(qū)別:

  • 靜態(tài)編譯:編譯器在編譯可執(zhí)行文件時,要把使用到的鏈接庫提取出來,鏈接打包進(jìn)可執(zhí)行文件中,編譯結(jié)果只有一個可執(zhí)行文件。
  • 動態(tài)編譯:可執(zhí)行文件需要附帶獨立的庫文件,不打包庫到可執(zhí)行文件中,減少可執(zhí)行文件體積,在執(zhí)行的時候再調(diào)用庫即可。

兩種方式有各自的優(yōu)點和缺點,前者不需要去管理不同版本庫的兼容性問題,后者可以減少內(nèi)存和存儲的占用(因為可以讓不同程序共享同一個庫),兩種方式孰優(yōu)孰弱,要對應(yīng)到具體的工程問題上,Go默認(rèn)的編譯方式是靜態(tài)編譯。

回到我們要討論的問題:C++的編譯為什么慢?

C++編譯慢的主要兩個大頭原因[6]:

  • 頭文件的include方式
  • 模板的編譯

C++使用include方式引用頭文件,會讓需要編譯的代碼有乘數(shù)級的增加,例如當(dāng)同一個頭文件被同一個項目下的N個文件include時,編譯器會將頭文件引入到每一份代碼中,所以同一個頭文件會被編譯N次(這在大多數(shù)時候都是不必要的);C++使用的模板是為了支持泛型編程,在編寫對不同類型的泛型函數(shù)時,可以提供很大的便利,但是這對于編譯器來說,會增加非常多不必要的編譯負(fù)擔(dān)。

當(dāng)然C++對這兩個問題有很多后續(xù)的優(yōu)化方法,但是這對于很多開發(fā)者來說,他們不想在這上面有過多時間和精力開銷。

大部分后來的編程語言在引入文件的方式上,使用了import module來代替include 頭文件的方式,import解決了重復(fù)編譯的問題,當(dāng)然Go也是使用的import方式;在模板的編譯問題上,由于Go在設(shè)計理念上遵循從簡入手,所以沒有將泛函編程納入到設(shè)計框架中,所以天生的沒有模版編譯帶來的時間開銷(沒有泛型支持也是很多人不滿Go語言的理由)。

在Go 的1.5 版本中,Go團(tuán)隊使用Go語言來編寫Go語言的編譯器(也叫自舉),相比于gccgo來說:

  • 提高了編譯速度,但執(zhí)行速度略有下降(性能細(xì)節(jié)優(yōu)化還不如gcc)
  • 增加了可編譯的平臺類型(以往受限于gcc)

在此之外,Go語言語法中的關(guān)鍵字也是非常少的(Go1.11版本里只有25個)[7],這也可以減少編譯器花費在語法解析上的時間開銷。

所以在我看來,Go編譯速度快,主要出于四個原因:

  • 使用了import的引用管理方式;
  • 沒有模板的編譯負(fù)擔(dān);
  • 1.5版本后的自舉編譯器優(yōu)化;
  • 更少的關(guān)鍵字。

所以為了加快編譯速度、放棄C++而轉(zhuǎn)入Go的同時,也要考慮一下是否要放棄泛型編程的優(yōu)點。

注:泛型可能在Go 2版本獲得支持。

Go的實際性能如何

Go的執(zhí)行速度,可以參考一個語言性能測試數(shù)據(jù)網(wǎng)站 —— The Computer Language Benchmarks Game[8]。

這個網(wǎng)站在不同的算法上對每個語言進(jìn)行測試,然后給出時間和內(nèi)存上的開銷數(shù)據(jù)比對。

比較的語言有C++、Java、Python。

首先是時間開銷:

注意:時間開銷的單位是s,并且Y軸為了方便進(jìn)行不同跨度上的比較,所以選取的是對數(shù)軸(即非線性軸,為1-10-100-1000的比較跨度)。

然后是內(nèi)存開銷:

注意:Y軸為了方便進(jìn)行不同跨度上的比較,所以選取的是對數(shù)軸(即非線性軸,為1000-10000-100000-1000000的比較跨度)。

需要注意的是,語言本身的性能只決定了一個程序的最高理論性能,程序具體的性能還要取決于這個程序的實現(xiàn)方法,所以當(dāng)各個語言的性能并沒有太大的差異時,性能往往只取決于程序?qū)崿F(xiàn)的方式。

通過兩個圖的數(shù)據(jù)可以分析:

  • Go雖然還無法達(dá)到C++那樣的極致性能,但是在大部分情況下已經(jīng)很接近了;
  • Go和Java在算法的時間開銷上難分伯仲,但在內(nèi)存的開銷上Java就要高得多了;
  • Go在上述的絕大部分情況下,至少時間和內(nèi)存開銷都比Python要優(yōu)秀得多;

Go的并發(fā)編程

Go的并發(fā)之所以比較受歡迎,網(wǎng)絡(luò)上的很多內(nèi)容集中在幾個方面:

  • 天生并發(fā)的設(shè)計
  • 輕量化的并發(fā)編程方式
  • 較高的并發(fā)性能
  • 輕量級線程Goroutines、并發(fā)通信Channels以及其他便捷的并發(fā)同步控制工具

由于Go在設(shè)計的時候就考慮到了并發(fā)的支持,或者說很多特性都是為了并發(fā)而設(shè)計,這和一些后期庫支持并發(fā)和第三方庫支持并發(fā)的語言不同。

所以Go的并發(fā)到底有多方便?在Go中使用并發(fā),只需要在普通的函數(shù)執(zhí)行前加上一個go關(guān)鍵字,就可以新建一個線程讓函數(shù)在其中執(zhí)行:

 

  1. func main() { 
  2.     go loop() // 啟動一個goroutine 
  3.     loop() 

這樣帶來的好處不僅僅是讓并發(fā)編程更方便了,在一些特定情況下,比如Go引用一些使用了并發(fā)的庫時,這些庫所使用的并發(fā)也是基于Go本身的并發(fā)設(shè)計,不會存在庫使用另一套并發(fā)實現(xiàn)的情況,這樣Go調(diào)度器在處理程序中的各種并發(fā)線程時,可以有更加統(tǒng)一化的管理方式。

不過Go的并發(fā)對于程序的實現(xiàn)要求還是比較高的,在使用一些通信Channel的場合,稍有疏忽就可能出現(xiàn)死鎖的問題,比如:

  1. fatal error: all goroutines are asleep - deadlock! 

Go的并發(fā)量可以比大部分語言里普通的線程實現(xiàn)要高,這受益于輕量級的Goroutine,輕量化主要是它所占用的空間要小得多,例如64位環(huán)境下的JVM,它會默認(rèn)固定為每個線程分配1MB的線程??臻g,而Goroutines大概只有4-8KB,之后再按需分配。足夠輕量化的線程在相同的內(nèi)存下也就可以有更高并發(fā)量(服務(wù)器CPU還沒有飽和的情況下),同時也可以減少很多上下文切換的時間開銷[9]。但是如果你的每個線程占用空間都非常大時(比如10MB,當(dāng)然這是非常規(guī)需求的情況下),Go的輕量化優(yōu)勢就沒有那么明顯了。

Go在并發(fā)上的優(yōu)點很明顯,也是Go的功能目標(biāo),從語言設(shè)計上支持了并發(fā),提供了統(tǒng)一便捷的工具,復(fù)雜的并發(fā)業(yè)務(wù)也需要在Go的一整套并發(fā)規(guī)范體系下進(jìn)行編程,當(dāng)然這肯定會犧牲部分實現(xiàn)自由度,但可以獲得性能的提高和維護(hù)成本的下降。

PS:關(guān)于Go調(diào)度器的內(nèi)容在這里并沒有被提及,因為很難用簡單的文字向讀者說明該調(diào)度方式和其他調(diào)度方式的優(yōu)劣,將在未來的某一篇中會細(xì)致地介紹Go調(diào)度器的內(nèi)容。

Go的垃圾回收

垃圾回收(英語:Garbage Collection,縮寫為GC),在計算機(jī)科學(xué)中是一種自動的存儲器管理機(jī)制。當(dāng)一個計算機(jī)上的動態(tài)存儲器不再需要時,就應(yīng)該予以釋放,以讓出存儲器,這種存儲器資源管理,稱為垃圾回收。垃圾回收器可以讓程序員減輕許多負(fù)擔(dān),也減少程序員犯錯的機(jī)會[10]。

在使用Go或者其他支持GC的語言時,不用再像C++一樣,手動地去釋放不需要的變量占用的內(nèi)容空間(free/delete)。

的確,這很方便(對于懶人和容易忘記主動釋放的人),但是也多了一些限制(暗箱操作的不透明性以及在GC處理上的性能開銷)。GC也不是萬能的,當(dāng)遇到一些對性能要求較高的場景,還是需要記得進(jìn)行一些主動釋放或優(yōu)化操作(比如說自定義內(nèi)存池)。

PS:將在未來的某一篇中會細(xì)致地介紹Go垃圾回收的細(xì)節(jié)(如果你們也覺得有必要的話)。

什么時候可以選擇Go?

Go有很多優(yōu)點,編譯快、性能好、天生并發(fā)以及垃圾回收,很多比較有特色的內(nèi)容也還沒有說到(比如gofmt)。

Go語言也有很多缺點,比如第三方庫支持還不夠多(相比于Python來說就少的太多了)、支持編譯的平臺還不夠廣、還有被稱為噩夢的依賴版本管理(已經(jīng)在改善了,但是還沒有達(dá)到完全可靠的程度)。

所以到底Go適合做什么,不適合做什么?

分析了這么多后,這個問題其實很難回答,但我們可以選擇先從不適合的領(lǐng)域把Go剔除掉,看看我們會剩下什么。

Go不適合做什么

  • 極致高性能優(yōu)化的場景,你可能需要使用C/C++,甚至是匯編;
  • 簡單流程的腳本工具、數(shù)值分析、深度學(xué)習(xí),可能Python更適合(至少目前是);
  • 搭一個博客或網(wǎng)站,PHP何嘗不是天下第一的語言呢;
  • 如果你想比較方便找到一份的后端工作,絕大部分公司的Java崗一直缺人(在實際生產(chǎn)過程中,目前Go仍沒有比Java表現(xiàn)得好太多,至少沒有好到讓一個部門/公司將核心業(yè)務(wù)重新轉(zhuǎn)向Go來進(jìn)行重構(gòu));
  • ...

你可以找到類似上面那樣的很多場景,你可能會發(fā)現(xiàn)Go并不能那么完美地替代掉誰。

Go適合做什么

最后,到了我們的終極問題,Go到底適合做什么?

讀到這里你可能會覺得,好像是我把Go的特性吹了一遍,然后突然告訴你可能Go不適合你。

Go天生并發(fā),面向并發(fā),所以Go的定位一直很清楚,從最淺顯的視角來看,至少Go作為一個有較高性能的并發(fā)后端來說,是具有非常大的誘惑力的。

尤其對于后端相關(guān)的程序員而言,在某些業(yè)務(wù)功能的初步實現(xiàn)上,簡潔的語法、內(nèi)置的并發(fā)、快速的編譯,都可以讓你更加高效快速地完成任務(wù)(前提是Go的內(nèi)容足以完成你的任務(wù)),不用再去擔(dān)憂編譯優(yōu)化和內(nèi)存回收、不用擔(dān)心過多的時間和內(nèi)存開銷、不用擔(dān)心不同版本庫之間的沖突(靜態(tài)編譯)以及不用擔(dān)心交叉編譯平臺適配問題。

大部分情況下,編寫一個服務(wù),你只需要:實現(xiàn)、編譯、部署、運行。

高效快速,足夠敏捷,這在企業(yè)的絕大部分項目的初期都是適用的,這也是大部分項目對開發(fā)初期的要求。當(dāng)一個項目或者服務(wù)真的可以發(fā)展下去,需求的確觸碰到Go的天花板時,再考慮使用更加好的語言或方法去優(yōu)化也為時不晚。

簡而言之,盡管Go的過于簡潔帶來了很多問題(有些人說的難聽點叫過于簡單),Go所具有的優(yōu)點,可以讓大部分人用編程語言這種工具,來解決對他們而言更加重要的問題。

Go語言不是銀彈,但它的確能有效地解決這些問題。

責(zé)任編輯:未麗燕 來源: segmentfault.com
相關(guān)推薦

2021-02-09 20:51:13

D 語言腳本編程語言

2016-09-27 21:25:08

Go語言Ken Thompso

2018-05-02 12:34:48

2024-01-02 10:38:22

Go語言數(shù)組

2009-01-09 23:06:41

服務(wù)器SCSI硬盤PC

2012-05-19 22:17:30

Android

2022-01-17 16:09:43

Go語言開發(fā)

2023-03-06 08:01:25

structGo語言

2024-01-02 17:28:12

芯片CPUAI計算

2021-05-11 06:57:15

HBaseBATJ公司

2024-07-02 13:27:38

2021-12-13 01:40:29

ElasticSear倒排索引

2012-11-13 10:27:45

PythonGo編程語言

2022-01-10 23:54:56

GoMap并發(fā)

2022-05-07 07:35:44

工具讀寫鎖Java

2024-01-01 08:10:40

Go語言map

2024-01-15 00:42:55

Go語言應(yīng)用程序

2024-01-05 08:45:35

Go語言map

2021-10-11 13:25:42

語言Go類型

2012-08-20 09:16:15

Go語言
點贊
收藏

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