亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

Go語言開發(fā)團(tuán)隊(duì)花了很長時(shí)間來解決當(dāng)今軟件開發(fā)人員面對(duì)的問題。開發(fā)人員在為項(xiàng)目選擇語言時(shí),不得不在快速開發(fā)和性能之間做出選擇。C和C++這類語言提供了很快的執(zhí)行速度,而Ruby和Python這類語言則擅長快速開發(fā)。Go語言在這兩者間架起了橋梁,不僅提供了高性能的語言,同時(shí)也讓開發(fā)更快速。

在探索Go語言的過程中,讀者會(huì)看到精心設(shè)計(jì)的特性以及簡(jiǎn)潔的語法。作為一門語言,Go不僅定義了能做什么,還定義了不能做什么。Go語言的語法簡(jiǎn)潔到只有幾個(gè)關(guān)鍵字,便于記憶。Go語言的編譯器速度非???,有時(shí)甚至?xí)屓烁杏X不到在編譯。所以,Go開發(fā)者能顯著減少等待項(xiàng)目構(gòu)建的時(shí)間。因?yàn)镚o語言內(nèi)置并發(fā)機(jī)制,所以不用被迫使用特定的線程庫,就能讓軟件擴(kuò)展,使用更多的資源。Go語言的類型系統(tǒng)簡(jiǎn)單且高效,不需要為面向?qū)ο箝_發(fā)付出額外的心智,讓開發(fā)者能專注于代碼復(fù)用。Go語言還自帶垃圾回收器,不需要用戶自己管理內(nèi)存。讓我們快速瀏覽一下這些關(guān)鍵特性。

1.1.1 開發(fā)速度

編譯一個(gè)大型的C或者C++項(xiàng)目所花費(fèi)的時(shí)間甚至比去喝杯咖啡的時(shí)間還長。圖1-1是XKCD中的一幅漫畫,描述了在辦公室里開小差的經(jīng)典借口。

Go 語言到底適合干什么?

 

圖1-1 努力工作?(來自XKCD)

Go語言使用了更加智能的編譯器,并簡(jiǎn)化了解決依賴的算法,最終提供了更快的編譯速度。編譯Go程序時(shí),編譯器只會(huì)關(guān)注那些直接被引用的庫,而不是像JAVA、C和C++那樣,要遍歷依賴鏈中所有依賴的庫。因此,很多Go程序可以在1秒內(nèi)編譯完。在現(xiàn)代硬件上,編譯整個(gè)Go語言的源碼樹只需要20秒。

因?yàn)闆]有從編譯代碼到執(zhí)行代碼的中間過程,用動(dòng)態(tài)語言編寫應(yīng)用程序可以快速看到輸出。代價(jià)是,動(dòng)態(tài)語言不提供靜態(tài)語言提供的類型安全特性,不得不經(jīng)常用大量的測(cè)試套件來避免在運(yùn)行的時(shí)候出現(xiàn)類型錯(cuò)誤這類bug。

想象一下,使用類似JavaScript這種動(dòng)態(tài)語言開發(fā)一個(gè)大型應(yīng)用程序,有一個(gè)函數(shù)期望接收一個(gè)叫作ID的字段。這個(gè)參數(shù)應(yīng)該是整數(shù),是字符串,還是一個(gè)UUID?要想知道答案,只能去看源代碼。可以嘗試使用一個(gè)數(shù)字或者字符串來執(zhí)行這個(gè)函數(shù),看看會(huì)發(fā)生什么。在Go語言里,完全不用為這件事情操心,因?yàn)榫幾g器就能幫用戶捕獲這種類型錯(cuò)誤。

1.1.2 并發(fā)

作為程序員,要開發(fā)出能充分利用硬件資源的應(yīng)用程序是一件很難的事情。現(xiàn)代計(jì)算機(jī)都擁有多個(gè)核,但是大部分編程語言都沒有有效的工具讓程序可以輕易利用這些資源。這些語言需要寫大量的線程同步代碼來利用多個(gè)核,很容易導(dǎo)致錯(cuò)誤。

Go語言對(duì)并發(fā)的支持是這門語言最重要的特性之一。goroutine很像線程,但是它占用的內(nèi)存遠(yuǎn)少于線程,使用它需要的代碼更少。通道(channel)是一種內(nèi)置的數(shù)據(jù)結(jié)構(gòu),可以讓用戶在不同的goroutine之間同步發(fā)送具有類型的消息。這讓編程模型更傾向于在goroutine之間發(fā)送消息,而不是讓多個(gè)goroutine爭(zhēng)奪同一個(gè)數(shù)據(jù)的使用權(quán)。讓我們看看這些特性的細(xì)節(jié)。

1.goroutine

goroutine是可以與其他goroutine并行執(zhí)行的函數(shù),同時(shí)也會(huì)與主程序(程序的入口)并行執(zhí)行。在其他編程語言中,你需要用線程來完成同樣的事情,而在Go語言中會(huì)使用同一個(gè)線程來執(zhí)行多個(gè)goroutine。例如,用戶在寫一個(gè)Web服務(wù)器,希望同時(shí)處理不同的Web請(qǐng)求,如果使用C或者Java,不得不寫大量的額外代碼來使用線程。在Go語言中,net/http庫直接使用了內(nèi)置的goroutine。每個(gè)接收到的請(qǐng)求都自動(dòng)在其自己的goroutine里處理。goroutine使用的內(nèi)存比線程更少,Go語言運(yùn)行時(shí)會(huì)自動(dòng)在配置的一組邏輯處理器上調(diào)度執(zhí)行g(shù)oroutine。每個(gè)邏輯處理器綁定到一個(gè)操作系統(tǒng)線程上(見圖1-2)。這讓用戶的應(yīng)用程序執(zhí)行效率更高,而開發(fā)工作量顯著減少。

Go 語言到底適合干什么?

 

圖1-2 在單一系統(tǒng)線程上執(zhí)行多個(gè)goroutine

如果想在執(zhí)行一段代碼的同時(shí),并行去做另外一些事情,goroutine是很好的選擇。下面是一個(gè)簡(jiǎn)單的例子:

func log(msg string) {
    ...這里是一些記錄日志的代碼
}

// 代碼里有些地方檢測(cè)到了錯(cuò)誤
go log("發(fā)生了可怕的事情")

關(guān)鍵字go是唯一需要去編寫的代碼,調(diào)度log函數(shù)作為獨(dú)立的goroutine去運(yùn)行,以便與其他goroutine并行執(zhí)行。這意味著應(yīng)用程序的其余部分會(huì)與記錄日志并行執(zhí)行,通常這種并行能讓最終用戶覺得性能更好。就像之前說的,goroutine占用的資源更少,所以常常能啟動(dòng)成千上萬個(gè)goroutine。我們會(huì)在第6章更加深入地探討goroutine和并發(fā)。

2.通道

通道是一種數(shù)據(jù)結(jié)構(gòu),可以讓goroutine之間進(jìn)行安全的數(shù)據(jù)通信。通道可以幫用戶避免其他語言里常見的共享內(nèi)存訪問的問題。

并發(fā)的最難的部分就是要確保其他并發(fā)運(yùn)行的進(jìn)程、線程或goroutine不會(huì)意外修改用戶的數(shù)據(jù)。當(dāng)不同的線程在沒有同步保護(hù)的情況下修改同一個(gè)數(shù)據(jù)時(shí),總會(huì)發(fā)生災(zāi)難。在其他語言中,如果使用全局變量或者共享內(nèi)存,必須使用復(fù)雜的鎖規(guī)則來防止對(duì)同一個(gè)變量的不同步修改。

為了解決這個(gè)問題,通道提供了一種新模式,從而保證并發(fā)修改時(shí)的數(shù)據(jù)安全。通道a

Go 語言到底適合干什么?

 

圖1-3 使用通道在goroutine之間安全地發(fā)送數(shù)據(jù)

圖1-3中有3個(gè)goroutine,還有2個(gè)不帶緩存的通道。第一個(gè)goroutine通過通道把數(shù)據(jù)傳給已經(jīng)在等待的第二個(gè)goroutine。在兩個(gè)goroutine間傳輸數(shù)據(jù)是同步的,一旦傳輸完成,兩個(gè)goroutine都會(huì)知道數(shù)據(jù)已經(jīng)完成傳輸。當(dāng)?shù)诙€(gè)goroutine利用這個(gè)數(shù)據(jù)完成其任務(wù)后,將這個(gè)數(shù)據(jù)傳給第三個(gè)正在等待的goroutine。這次傳輸依舊是同步的,兩個(gè)goroutine都會(huì)確認(rèn)數(shù)據(jù)傳輸完成。這種在goroutine之間安全傳輸數(shù)據(jù)的方法不需要任何鎖或者同步機(jī)制。

需要強(qiáng)調(diào)的是,通道并不提供跨goroutine的數(shù)據(jù)訪問保護(hù)機(jī)制。如果通過通道傳輸數(shù)據(jù)的一份副本,那么每個(gè)goroutine都持有一份副本,各自對(duì)自己的副本做修改是安全的。當(dāng)傳輸?shù)氖侵赶驍?shù)據(jù)的指針時(shí),如果讀和寫是由不同的goroutine完成的,每個(gè)goroutine依舊需要額外的同步動(dòng)作。

1.1.3 Go語言的類型系統(tǒng)

Go語言提供了靈活的、無繼承的類型系統(tǒng),無需降低運(yùn)行性能就能最大程度上復(fù)用代碼。這個(gè)類型系統(tǒng)依然支持面向?qū)ο箝_發(fā),但避免了傳統(tǒng)面向?qū)ο蟮膯栴}。如果你曾經(jīng)在復(fù)雜的Java和C++程序上花數(shù)周時(shí)間考慮如何抽象類和接口,你就能意識(shí)到Go語言的類型系統(tǒng)有多么簡(jiǎn)單。Go 開發(fā)者使用組合(composition)設(shè)計(jì)模式,只需簡(jiǎn)單地將一個(gè)類型嵌入到另一個(gè)類型,就能復(fù)用所有的功能。其他語言也能使用組合,但是不得不和繼承綁在一起使用,結(jié)果使整個(gè)用法非常復(fù)雜,很難使用。在Go語言中,一個(gè)類型由其他更微小的類型組合而成,避免了傳統(tǒng)的基于繼承的模型。

另外,Go語言還具有獨(dú)特的接口實(shí)現(xiàn)機(jī)制,允許用戶對(duì)行為進(jìn)行建模,而不是對(duì)類型進(jìn)行建模。在Go語言中,不需要聲明某個(gè)類型實(shí)現(xiàn)了某個(gè)接口,編譯器會(huì)判斷一個(gè)類型的實(shí)例是否符合正在使用的接口。Go標(biāo)準(zhǔn)庫里的很多接口都非常簡(jiǎn)單,只開放幾個(gè)函數(shù)。從實(shí)踐上講,尤其對(duì)那些使用類似Java的面向?qū)ο笳Z言的人來說,需要一些時(shí)間才能習(xí)慣這個(gè)特性。

1.類型簡(jiǎn)單

Go語言不僅有類似int和string這樣的內(nèi)置類型,還支持用戶定義的類型。在Go語言中,用戶定義的類型通常包含一組帶類型的字段,用于存儲(chǔ)數(shù)據(jù)。Go語言的用戶定義的類型看起來和C語言的結(jié)構(gòu)很像,用起來也很相似。不過Go語言的類型可以聲明操作該類型數(shù)據(jù)的方法。傳統(tǒng)語言使用繼承來擴(kuò)展結(jié)構(gòu)——Client繼承自User,User繼承自Entity,Go語言與此不同,Go開發(fā)者構(gòu)建更小的類型——Customer和Admin,然后把這些小類型組合成更大的類型。圖1-4展示了繼承和組合之間的不同。

Go 語言到底適合干什么?

 

圖1-4 繼承和組合的對(duì)比

2.Go接口對(duì)一組行為建模

接口用于描述類型的行為。如果一個(gè)類型的實(shí)例實(shí)現(xiàn)了一個(gè)接口,意味著這個(gè)實(shí)例可以執(zhí)行一組特定的行為。你甚至不需要去聲明這個(gè)實(shí)例實(shí)現(xiàn)某個(gè)接口,只需要實(shí)現(xiàn)這組行為就好。其他的語言把這個(gè)特性叫作鴨子類型——如果它叫起來像鴨子,那它就可能是只鴨子。Go語言的接口也是這么做的。在Go語言中,如果一個(gè)類型實(shí)現(xiàn)了一個(gè)接口的所有方法,那么這個(gè)類型的實(shí)例就可以存儲(chǔ)在這個(gè)接口類型的實(shí)例中,不需要額外聲明。

在類似Java這種嚴(yán)格的面向?qū)ο笳Z言中,所有的設(shè)計(jì)都圍繞接口展開。在編碼前,用戶經(jīng)常不得不思考一個(gè)龐大的繼承鏈。下面是一個(gè)Java接口的例子:

interface User {
    public void login();
    public void logout();
}

在Java中要實(shí)現(xiàn)這個(gè)接口,要求用戶的類必須滿足User接口里的所有約束,并且顯式聲明這個(gè)類實(shí)現(xiàn)了這個(gè)接口。而Go語言的接口一般只會(huì)描述一個(gè)單一的動(dòng)作。在Go語言中,最常使用的接口之一是io.Reader。這個(gè)接口提供了一個(gè)簡(jiǎn)單的方法,用來聲明一個(gè)類型有數(shù)據(jù)可以讀取。標(biāo)準(zhǔn)庫內(nèi)的其他函數(shù)都能理解這個(gè)接口。這個(gè)接口的定義如下:

type Reader interface {
    Read(p []byte) (n int, err error)
}

為了實(shí)現(xiàn)io.Reader這個(gè)接口,你只需要實(shí)現(xiàn)一個(gè)Read方法,這個(gè)方法接受一個(gè)byte切片,返回一個(gè)整數(shù)和可能出現(xiàn)的錯(cuò)誤。

這和傳統(tǒng)的面向?qū)ο缶幊陶Z言的接口系統(tǒng)有本質(zhì)的區(qū)別。Go語言的接口更小,只傾向于定義一個(gè)單一的動(dòng)作。實(shí)際使用中,這更有利于使用組合來復(fù)用代碼。用戶幾乎可以給所有包含數(shù)據(jù)的類型實(shí)現(xiàn)io.Reader接口,然后把這個(gè)類型的實(shí)例傳給任意一個(gè)知道如何讀取io.Reader的Go函數(shù)。

Go語言的整個(gè)網(wǎng)絡(luò)庫都使用了io.Reader接口,這樣可以將程序的功能和不同網(wǎng)絡(luò)的實(shí)現(xiàn)分離。這樣的接口用起來有趣、優(yōu)雅且自由。文件、緩沖區(qū)、套接字以及其他的數(shù)據(jù)源都實(shí)現(xiàn)了io.Reader接口。使用同一個(gè)接口,可以高效地操作數(shù)據(jù),而不用考慮到底數(shù)據(jù)來自哪里。

1.1.4 內(nèi)存管理

不當(dāng)?shù)膬?nèi)存管理會(huì)導(dǎo)致程序崩潰或者內(nèi)存泄漏,甚至讓整個(gè)操作系統(tǒng)崩潰。Go語言擁有現(xiàn)代化的垃圾回收機(jī)制,能幫你解決這個(gè)難題。在其他系統(tǒng)語言(如C或者C++)中,使用內(nèi)存前要先分配這段內(nèi)存,而且使用完畢后要將其釋放掉。哪怕只做錯(cuò)了一件事,都可能導(dǎo)致程序崩潰或者內(nèi)存泄漏。可惜,追蹤內(nèi)存是否還被使用本身就是十分艱難的事情,而要想支持多線程和高并發(fā),更是讓這件事難上加難。雖然Go語言的垃圾回收會(huì)有一些額外的開銷,但是編程時(shí),能顯著降低開發(fā)難度。Go語言把無趣的內(nèi)存管理交給專業(yè)的編譯器去做,而讓程序員專注于更有趣的事情。

本文摘自《Go語言實(shí)戰(zhàn)》

分享到:
標(biāo)簽:語言
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績?cè)u(píng)定