精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Go 通道是糟糕的,你應(yīng)該也覺得很糟糕

開發(fā) 后端
Go 絕對是我使用過的最不糟糕的的編程語言。在我寫作本文時,我是想遏制我所看到的一種趨勢,那就是過度使用 Go 的一些較復(fù)雜的部分。我仍然認(rèn)為 通道Channel可以更好,但是總體而言,Go 很棒。這就像你最喜歡的工具箱中有 這個工具;它可以有用途,它仍然可以成為你最喜歡的工具箱!

[[373820]]

更新:如果你是從一篇題為 《糟糕的 Go 語言》 的匯編文章看到這篇博文的話,那么我想表明的是,我很慚愧被列在這樣的名單上。Go 絕對是我使用過的最不糟糕的的編程語言。在我寫作本文時,我是想遏制我所看到的一種趨勢,那就是過度使用 Go 的一些較復(fù)雜的部分。我仍然認(rèn)為 通道Channel可以更好,但是總體而言,Go 很棒。這就像你最喜歡的工具箱中有 這個工具;它可以有用途(甚至還可能有更多的用途),它仍然可以成為你最喜歡的工具箱!

更新 2:如果我沒有指出這項(xiàng)對真實(shí)問題的優(yōu)秀調(diào)查,那我將是失職的:《理解 Go 中的實(shí)際并發(fā)錯誤》。這項(xiàng)調(diào)查的一個重要發(fā)現(xiàn)是...Go 通道會導(dǎo)致很多錯誤。

從 2010 年中后期開始,我就斷斷續(xù)續(xù)地在使用 Google 的 Go 編程語言,自 2012 年 1 月開始(在 Go 1.0 之前!),我就用 Go 為 Space Monkey 編寫了合規(guī)的產(chǎn)品代碼。我對 Go 的最初體驗(yàn)可以追溯到我在研究 Hoare 的 通信順序進(jìn)程 并發(fā)模型和 Matt Might 的 UCombinator 研究組 下的 π-演算 時,作為我(現(xiàn)在已重定向)博士工作的一部分,以更好地支持多核開發(fā)。Go 就是在那時發(fā)布的(多么巧合啊!),我當(dāng)即就開始學(xué)習(xí)嘗試了。

它很快就成為了 Space Monkey 開發(fā)的核心部分。目前,我們在 Space Monkey 的生產(chǎn)系統(tǒng)有超過 42.5 萬行的純 Go 代碼( 包括我們所有的 vendored 庫中的代碼量,這將使它接近 150 萬行),所以也并不是你見過的最多的 Go 代碼,但是對于相對年輕的語言,我們是重度用戶。我們之前 寫了我們的 Go 使用情況。也開源了一些使用率很高的庫;許多人似乎是我們的 OpenSSL 綁定(比 crypto/tls 更快,但請保持 openssl 本身是最新的!)、我們的 錯誤處理庫日志庫 和 度量標(biāo)準(zhǔn)收集庫/zipkin 客戶端 的粉絲。我們使用 Go、我們熱愛 Go、我們認(rèn)為它是目前為止我們使用過的最不糟糕的、符合我們需求的編程語言。

盡管我也不認(rèn)為我能說服自己不要提及我的廣泛避免使用 goroutine-local-storage 庫 (盡管它是一個你不應(yīng)該使用的魔改技巧,但它是一個漂亮的魔改),希望我的其他經(jīng)歷足以證明我在解釋我故意煽動性的帖子標(biāo)題之前知道我在說什么。

等等,什么?

如果你在大街上問一個有名的程序員,Go 有什么特別之處? 她很可能會告訴你 Go 最出名的是通道Channels 和 goroutine。 Go 的理論基礎(chǔ)很大程度上是建立在 Hoare 的 CSP(通信順序進(jìn)程Communicating Sequential Processes)模型上的,該模型本身令人著迷且有趣,我堅信,到目前為止,它產(chǎn)生的收益遠(yuǎn)遠(yuǎn)超過了我們的預(yù)期。

CSP(和 π-演算)都使用通信作為核心同步原語,因此 Go 會有通道是有道理的。Rob Pike 對 CSP 著迷(有充分的理由)相當(dāng)深 已經(jīng)有一段時間了。(當(dāng)時 和 現(xiàn)在)。

但是從務(wù)實(shí)的角度來看(也是 Go 引以為豪的),Go 把通道搞錯了。在這一點(diǎn)上,通道的實(shí)現(xiàn)在我的書中幾乎是一個堅實(shí)的反模式。為什么這么說呢?親愛的讀者,讓我細(xì)數(shù)其中的方法。

你可能最終不會只使用通道

Hoare 的 “通信順序進(jìn)程” 是一種計算模型,實(shí)際上,唯一的同步原語是在通道上發(fā)送或接收的。一旦使用 互斥量mutex信號量semaphore 或 條件變量condition variable、bam,你就不再處于純 CSP 領(lǐng)域。 Go 程序員經(jīng)常通過高呼 “通過交流共享內(nèi)存” 的 緩存的思想 來宣揚(yáng)這種模式和哲學(xué)。

那么,讓我們嘗試在 Go 中僅使用 CSP 編寫一個小程序!讓我們成為高分接收者。我們要做的就是跟蹤我們看到的最大的高分值。如此而已。

首先,我們將創(chuàng)建一個 Game 結(jié)構(gòu)體。

  1. type Game struct {
  2. bestScore int
  3. scores chan int
  4. }

bestScore 不會受到互斥量mutex的保護(hù)!這很好,因?yàn)槲覀冎恍枰粋€ goroutine 來管理其狀態(tài)并通過通道來接收新的分值即可。

  1. func (g *Game) run() {
  2. for score := range g.scores {
  3. if g.bestScore < score {
  4. g.bestScore = score
  5. }
  6. }
  7. }

好的,現(xiàn)在我們將創(chuàng)建一個有用的構(gòu)造函數(shù)來開始 Game

  1. func NewGame() (g *Game) {
  2. g = &Game{
  3. bestScore: 0,
  4. scores: make(chan int),
  5. }
  6. go g.run()
  7. return g
  8. }

接下來,假設(shè)有人給了我們一個可以返回分?jǐn)?shù)的 Player。它也可能會返回錯誤,因?yàn)榭赡軅魅氲?TCP 流可能會死掉或發(fā)生某些故障,或者玩家退出。

  1. type Player interface {
  2. NextScore() (score int, err error)
  3. }

為了處理 Player,我們假設(shè)所有錯誤都是致命的,并將獲得的比分向下傳遞到通道。

  1. func (g *Game) HandlePlayer(p Player) error {
  2. for {
  3. score, err := p.NextScore()
  4. if err != nil {
  5. return err
  6. }
  7. g.scores <- score
  8. }
  9. }

好極了!現(xiàn)在我們有了一個 Game 類型,可以以線程安全的方式跟蹤 Player 獲得的最高分?jǐn)?shù)。

你圓滿完成了自己的開發(fā)工作,并開始擁有客戶。你將這個游戲服務(wù)器公開,就取得了令人難以置信的成功!你的游戲服務(wù)器上也許正在創(chuàng)建許多游戲。

很快,你發(fā)現(xiàn)人們有時會離開你的游戲。許多游戲不再有任何玩家在玩,但沒有任何東西可以阻止游戲運(yùn)行的循環(huán)。死掉的 (*Game).run goroutines 讓你不知所措。

挑戰(zhàn): 在無需互斥量或 panics 的情況下修復(fù)上面的 goroutine 泄漏。實(shí)際上,可以滾動到上面的代碼,并想出一個僅使用通道來解決此問題的方案。

我等著。

就其價值而言,它完全可以只通過通道來完成,但是請觀察以下解決方案的簡單性,它甚至沒有這個問題:

  1. type Game struct {
  2. mtx sync.Mutex
  3. bestScore int
  4. }
  5.  
  6. func NewGame() *Game {
  7. return &Game{}
  8. }
  9.  
  10. func (g *Game) HandlePlayer(p Player) error {
  11. for {
  12. score, err := p.NextScore()
  13. if err != nil {
  14. return err
  15. }
  16. g.mtx.Lock()
  17. if g.bestScore < score {
  18. g.bestScore = score
  19. }
  20. g.mtx.Unlock()
  21. }
  22. }

你想選擇哪一個?不要被欺騙了,以為通道的解決方案可以使它在更復(fù)雜的情況下更具可讀性和可理解性。拆解Teardown是非常困難的。這種拆解若用互斥量mutex來做那只是小菜一碟,但最困難的是只使用 Go 專用通道來解決。另外,如果有人回復(fù)說發(fā)送通道的通道更容易推理,我馬上就是感到頭疼。

重要的是,這個特殊的情況可能真的 很容易 解決,而通道有一些運(yùn)行時的幫助,而 Go 沒有提供!不幸的是,就目前的情況來看,與 Go 的 CSP 版本相比,使用傳統(tǒng)的同步原語synchronization primitives可以更好地解決很多問題,這是令人驚訝的。稍后,我們將討論 Go 可以做些什么來簡化此案例。

練習(xí): 還在懷疑? 試著讓上面兩種解決方案(只使用通道與只使用互斥量channel-only vs mutex-only)在一旦 bestScore 大于或等于 100 時,就停止向 Players 索要分?jǐn)?shù)。繼續(xù)打開你的文本編輯器。這是一個很小的玩具問題。

這里的總結(jié)是,如果你想做任何實(shí)際的事情,除了通道之外,你還會使用傳統(tǒng)的同步原語。

通道比你自己實(shí)現(xiàn)要慢一些

Go 如此重視 CSP 理論,我認(rèn)為其中一點(diǎn)就是,運(yùn)行時應(yīng)該可以通過通道做一些殺手級的調(diào)度優(yōu)化。也許通道并不總是最直接的原語,但肯定是高效且快速的,對吧?

正如 Dustin Hiatt 在 Tyler Treat’s post about Go 上指出的那樣,

在幕后,通道使用鎖來序列化訪問并提供線程安全性。 因此,通過使用通道同步對內(nèi)存的訪問,你實(shí)際上就是在使用鎖。 被包裝在線程安全隊(duì)列中的鎖。 那么,與僅僅使用標(biāo)準(zhǔn)庫 sync 包中的互斥量相比,Go 的花式鎖又如何呢? 以下數(shù)字是通過使用 Go 的內(nèi)置基準(zhǔn)測試功能,對它們的單個集合連續(xù)調(diào)用 Put 得出的。

  1. > BenchmarkSimpleSet-8 3000000 391 ns/op
  2. > BenchmarkSimpleChannelSet-8 1000000 1699 ns/o
  3. >

無緩沖通道的情況與此類似,甚至是在爭用而不是串行運(yùn)行的情況下執(zhí)行相同的測試。

也許 Go 調(diào)度器會有所改進(jìn),但與此同時,良好的舊互斥量和條件變量是非常好、高效且快速。如果你想要提高性能,請使用久經(jīng)考驗(yàn)的方法。

通道與其他并發(fā)原語組合不佳

好的,希望我已經(jīng)說服了你,有時候,你至少還會與除了通道之外的原語進(jìn)行交互。標(biāo)準(zhǔn)庫似乎顯然更喜歡傳統(tǒng)的同步原語而不是通道。

你猜怎么著,正確地將通道與互斥量和條件變量一起使用,其實(shí)是有一定的挑戰(zhàn)性的。

關(guān)于通道的一個有趣的事情是,通道發(fā)送是同步的,這在 CSP 中是有很大意義的。通道發(fā)送和通道接收的目的是為了成為同步屏蔽,發(fā)送和接收應(yīng)該發(fā)生在同一個虛擬時間。如果你是在執(zhí)行良好的 CSP 領(lǐng)域,那就太好了。

實(shí)事求是地說,Go 通道也有多種緩沖方式。你可以分配一個固定的空間來考慮可能的緩沖,以便發(fā)送和接收是不同的事件,但緩沖區(qū)大小是有上限的。Go 并沒有提供一種方法來讓你擁有任意大小的緩沖區(qū) —— 你必須提前分配緩沖區(qū)大小。 這很好,我在郵件列表上看到有人在爭論,因?yàn)闊o論如何內(nèi)存都是有限的

What。

這是個糟糕的答案。有各種各樣的理由來使用一個任意緩沖的通道。如果我們事先知道所有的事情,為什么還要使用 malloc 呢?

沒有任意緩沖的通道意味著在 任何 通道上的幼稚發(fā)送可能會隨時阻塞。你想在一個通道上發(fā)送,并在互斥下更新其他一些記賬嗎?小心!你的通道發(fā)送可能被阻塞!

  1. // ...
  2. s.mtx.Lock()
  3. // ...
  4. s.ch <- val // might block!
  5. s.mtx.Unlock()
  6. // ...

這是哲學(xué)家晚餐大戰(zhàn)的秘訣。如果你使用了鎖,則應(yīng)該迅速更新狀態(tài)并釋放它,并且盡可能不要在鎖下做任何阻塞。

有一種方法可以在 Go 中的通道上進(jìn)行非阻塞發(fā)送,但這不是默認(rèn)行為。假設(shè)我們有一個通道 ch := make(chan int),我們希望在其上無阻塞地發(fā)送值 1。以下是在不阻塞的情況下你必須要做的最小量的輸入:

  1. select {
  2. case ch <- 1: // it sent
  3. default: // it didn't
  4. }

對于剛?cè)腴T的 Go程序員來說,這并不是自然而然就能想到的事情。

綜上所述,因?yàn)橥ǖ郎系暮芏嗖僮鞫紩枞孕枰獙φ軐W(xué)家及其就餐仔細(xì)推理,才能在互斥量的保護(hù)下,成功地將通道操作與之并列使用,而不會造成死鎖。

嚴(yán)格來說,回調(diào)更強(qiáng)大,不需要不必要的 goroutines

每當(dāng) API 使用通道時,或者每當(dāng)我指出通道使某些事情變得困難時,總會有人會指出我應(yīng)該啟動一個 goroutine 來讀取該通道,并在讀取該通道時進(jìn)行所需的任何轉(zhuǎn)換或修復(fù)。

呃,不。如果我的代碼位于熱路徑中怎么辦?需要通道的實(shí)例很少,如果你的 API 可以設(shè)計為使用互斥量mutexes信號量semaphores回調(diào)callbacks,而不使用額外的 goroutine (因?yàn)樗惺录吘壎际怯?API 事件觸發(fā)的),那么使用通道會迫使我在資源使用中添加另一個內(nèi)存分配堆棧。是的,goroutine 比線程輕得多,但更輕量并不意味著是最輕量。

正如我以前 在一篇關(guān)于使用通道的文章的評論中爭論過的(呵呵,互聯(lián)網(wǎng)),如果你使用回調(diào)而不是通道,你的 API 總是 可以更通用,總是 更靈活,而且占用的資源也會大大減少。“總是” 是一個可怕的詞,但我在這里是認(rèn)真的。有證據(jù)級的東西在進(jìn)行。

如果有人向你提供了一個基于回調(diào)的 API,而你需要一個通道,你可以提供一個回調(diào),在通道上發(fā)送,開銷不大,靈活性十足。

另一方面,如果有人提供了一個基于通道的 API 給你,而你需要一個回調(diào),你必須啟動一個 goroutine 來讀取通道,并且 你必須希望當(dāng)你完成讀取時,沒有人試圖在通道上發(fā)送更多的東西,這樣你就會導(dǎo)致阻塞的 goroutine 泄漏。

對于一個超級簡單的實(shí)際例子,請查看 context 接口(順便說一下,它是一個非常有用的包,你應(yīng)該用它來代替 goroutine 本地存儲)。

  1. type Context interface {
  2. ...
  3. // Done returns a channel that closes when this work unit should be canceled.
  4. // Done 返回一個通道,該通道在應(yīng)該取消該工作單元時關(guān)閉。
  5. Done() <-chan struct{}
  6.  
  7. // Err returns a non-nil error when the Done channel is closed
  8. // 當(dāng) Done 通道關(guān)閉時,Err 返回一個非 nil 錯誤
  9. Err() error
  10. ...
  11. }

想象一下,你要做的只是在 Done() 通道觸發(fā)時記錄相應(yīng)的錯誤。你該怎么辦?如果你沒有在通道中選擇的好地方,則必須啟動 goroutine 進(jìn)行處理:

  1. go func() {
  2. <-ctx.Done()
  3. logger.Errorf("canceled: %v", ctx.Err())
  4. }()

如果 ctx 在不關(guān)閉返回 Done() 通道的情況下被垃圾回收怎么辦?哎呀!這正是一個 goroutine 泄露!

現(xiàn)在假設(shè)我們更改了 Done 的簽名:

  1. // Done calls cb when this work unit should be canceled.
  2. Done(cb func())

首先,現(xiàn)在日志記錄非常容易。看看:ctx.Done(func() { log.Errorf ("canceled:%v", ctx.Err()) })。但是假設(shè)你確實(shí)需要某些選擇行為。你可以這樣調(diào)用它:

  1. ch := make(chan struct{})
  2. ctx.Done(func() { close(ch) })

瞧!通過使用回調(diào),不會失去表現(xiàn)力。 ch 的工作方式類似于用于返回的通道 Done(),在日志記錄的情況下,我們不需要啟動整個新堆棧。我必須保留堆棧跟蹤信息(如果我們的日志包傾向于使用它們);我必須避免將其他堆棧分配和另一個 goroutine 分配給調(diào)度程序。

下次你使用通道時,問問你自己,如果你用互斥量和條件變量代替,是否可以消除一些 goroutine ? 如果答案是肯定的,那么修改這些代碼將更加有效。而且,如果你試圖使用通道只是為了在集合中使用 range 關(guān)鍵字,那么我將不得不請你放下鍵盤,或者只是回去編寫 Python 書籍。

通道 API 不一致,只是 cray-cray

在通道已關(guān)閉的情況下,執(zhí)行關(guān)閉或發(fā)送消息將會引發(fā) panics!為什么呢? 如果想要關(guān)閉通道,你需要在外部同步它的關(guān)閉狀態(tài)(使用互斥量等,這些互斥量的組合不是很好!),這樣其他寫入者才不會寫入或關(guān)閉已關(guān)閉的通道,或者只是向前沖,關(guān)閉或?qū)懭胍殃P(guān)閉的通道,并期望你必須恢復(fù)所有引發(fā)的 panics。

這是多么怪異的行為。 Go 中幾乎所有其他操作都有避免 panic 的方法(例如,類型斷言具有 , ok = 模式),但是對于通道,你只能自己動手處理它。

好吧,所以當(dāng)發(fā)送失敗時,通道會出現(xiàn) panic。我想這是有一定道理的。但是,與幾乎所有其他帶有 nil 值的東西不同,發(fā)送到 nil 通道不會引發(fā) panic。相反,它將永遠(yuǎn)阻塞!這很違反直覺。這可能是有用的行為,就像在你的除草器上附加一個開罐器,可能有用(在 Skymall 可以找到)一樣,但這肯定是意想不到的。與 nil 映射(執(zhí)行隱式指針解除引用),nil 接口(隱式指針解除引用),未經(jīng)檢查的類型斷言以及其他所有類型交互不同,nil 通道表現(xiàn)出實(shí)際的通道行為,就好像為該操作實(shí)例化了一個全新的通道一樣。

接收的情況稍微好一點(diǎn)。在已關(guān)閉的通道上執(zhí)行接收會發(fā)生什么?好吧,那會是有效操作——你將得到一個零值。好吧,我想這是有道理的。獎勵!接收允許你在收到值時進(jìn)行 , ok = 樣式的檢查,以確定通道是否打開。謝天謝地,我們在這里得到了 , ok =

但是,如果你從 nil 渠道接收會發(fā)生什么呢? 也是永遠(yuǎn)阻塞! 耶!不要試圖利用這樣一個事實(shí):如果你關(guān)閉了通道,那么你的通道是 nil!

通道有什么好處?

當(dāng)然,通道對于某些事情是有好處的(畢竟它們是一個通用容器),有些事情你只能用它們來做(比如 select)。

它們是另一種特殊情況下的通用數(shù)據(jù)結(jié)構(gòu)

Go 程序員已經(jīng)習(xí)慣于對泛型的爭論,以至于我一提起這個詞就能感覺到 PTSD(創(chuàng)傷后應(yīng)激障礙)的到來。我不是來談?wù)撨@件事的,所以擦擦額頭上的汗,讓我們繼續(xù)前進(jìn)吧。

無論你對泛型的看法是什么,Go 的映射、切片和通道都是支持泛型元素類型的數(shù)據(jù)結(jié)構(gòu),因?yàn)樗鼈円呀?jīng)被特殊封裝到語言中了。

在一種不允許你編寫自己的泛型容器的語言中,任何允許你更好地管理事物集合的東西都是有價值的。在這里,通道是一個支持任意值類型的線程安全數(shù)據(jù)結(jié)構(gòu)。

所以這很有用!我想這可以省去一些陳詞濫調(diào)。

我很難把這算作是通道的勝利。

Select

使用通道可以做的主要事情是 select 語句。在這里,你可以等待固定數(shù)量的事件輸入。它有點(diǎn)像 epoll,但你必須預(yù)先知道要等待多少個套接字。

這是真正有用的語言功能。如果不是 select,通道將被徹底清洗。但是我的天吶,讓我告訴你,第一次決定可能需要在多個事物中選擇,但是你不知道有多少項(xiàng),因此必須使用 reflect.Select

通道如何才能更好?

很難說 Go 語言團(tuán)隊(duì)可以為 Go 2.0 做的最具戰(zhàn)術(shù)意義的事情是什么(Go 1.0 兼容性保證很好,但是很費(fèi)勁),但這并不能阻止我提出一些建議。

在條件變量上的 Select !

我們可以不需要通道!這是我提議我們擺脫一些“圣牛sacred cows”(LCTT 譯注:神圣不可質(zhì)疑的事物)的地方,但是讓我問你,如果你可以選擇任何自定義同步原語,那會有多棒?(答:太棒了。)如果有的話,我們根本就不需要通道了。

GC 可以幫助我們嗎?

在第一個示例中,如果我們能夠使用定向類型的通道垃圾回收(GC)來幫助我們進(jìn)行清理,我們就可以輕松地解決通道的高分服務(wù)器清理問題。

如你所知,Go 具有定向類型的通道。 你可以使用僅支持讀取的通道類型(<-chan)和僅支持寫入的通道類型(chan<-)。 這太棒了!

Go 也有垃圾回收功能。 很明顯,某些類型的記賬方式太繁瑣了,我們不應(yīng)該讓程序員去處理它們。 我們清理未使用的內(nèi)存! 垃圾回收非常有用且整潔。

那么,為什么不幫助清理未使用或死鎖的通道讀取呢? 與其讓 make(chan Whatever) 返回一個雙向通道,不如讓它返回兩個單向通道(chanReader, chanWriter:= make(chan Type))。

讓我們重新考慮一下最初的示例:

  1. type Game struct {
  2. bestScore int
  3. scores chan<- int
  4. }
  5.  
  6. func run(bestScore *int, scores <-chan int) {
  7. // 我們不會直接保留對游戲的引用,因?yàn)檫@樣我們就會保留著通道的發(fā)送端。
  8. for score := range scores {
  9. if *bestScore < score {
  10. *bestScore = score
  11. }
  12. }
  13. }
  14.  
  15. func NewGame() (g *Game) {
  16. // 這種 make(chan) 返回風(fēng)格是一個建議
  17. scoreReader, scoreWriter := make(chan int)
  18. g = &Game{
  19. bestScore: 0,
  20. scores: scoreWriter,
  21. }
  22. go run(&g.bestScore, scoreReader)
  23. return g
  24. }
  25.  
  26. func (g *Game) HandlePlayer(p Player) error {
  27. for {
  28. score, err := p.NextScore()
  29. if err != nil {
  30. return err
  31. }
  32. g.scores <- score
  33. }
  34. }

如果垃圾回收關(guān)閉了一個通道,而我們可以證明它永遠(yuǎn)不會有更多的值,那么這個解決方案是完全可行的。是的,是的,run 中的評論暗示著有一把相當(dāng)大的槍瞄準(zhǔn)了你的腳,但至少現(xiàn)在這個問題可以很容易地解決了,而以前確實(shí)不是這樣。此外,一個聰明的編譯器可能會做出適當(dāng)?shù)淖C明,以減少這種腳槍造成的損害。

其他小問題

  • Dup 通道嗎? —— 如果我們可以在通道上使用等效于 dup 的系統(tǒng)調(diào)用,那么我們也可以很容易地解決多生產(chǎn)者問題。 每個生產(chǎn)者可以關(guān)閉自己的 dup 版通道,而不會破壞其他生產(chǎn)者。
  • 修復(fù)通道 API! —— 關(guān)閉不是冪等的嗎? 在已關(guān)閉的通道上發(fā)送信息引起的 panics 沒有辦法避免嗎? 啊!
  • 任意緩沖的通道 —— 如果我們可以創(chuàng)建沒有固定的緩沖區(qū)大小限制的緩沖通道,那么我們可以創(chuàng)建非阻塞的通道。

那我們該怎么向大家介紹 Go 呢?

如果你還沒有,請看看我目前最喜歡的編程文章:《你的函數(shù)是什么顏色》。雖然不是專門針對 Go,但這篇博文比我更有說服力地闡述了為什么 goroutines 是 Go 最好的特性(這也是 Go 在某些應(yīng)用程序中優(yōu)于 Rust 的方式之一)。

如果你還在使用這樣的一種編程語言寫代碼,它強(qiáng)迫你使用類似 yield 關(guān)鍵字來獲得高性能、并發(fā)性或事件驅(qū)動的模型,那么你就是活在過去,不管你或其他人是否知道這一點(diǎn)。到目前為止,Go 是我所見過的實(shí)現(xiàn) M:N 線程模型(非 1:1 )的語言中最好的入門者之一,而且這種模型非常強(qiáng)大。

所以,跟大家說說 goroutines 吧。

如果非要我選擇 Go 的另一個主要特性,那就是接口。靜態(tài)類型的 鴨子模型duck typing 使得擴(kuò)展、使用你自己或他人的項(xiàng)目變得如此有趣而令人驚奇,這也許值得我改天再寫一組完全不同的文章來介紹它。

所以…

我一直看到人們爭先恐后沖進(jìn) Go,渴望充分利用通道來發(fā)揮其全部潛力。這是我對你的建議。

夠了!

當(dāng)你在編寫 API 和接口時,盡管“絕不”的建議可能很糟糕,但我非常肯定,通道從來沒有什么時候好過,我用過的每一個使用通道的 Go API,最后都不得不與之抗?fàn)帯N覐膩頉]有想過“哦 太好了,這里是一個通道;”它總是被一些變體取代,這是什么新鮮的地獄?

所以,請在適當(dāng)?shù)牡胤剑⑶抑辉谶m當(dāng)?shù)牡胤绞褂猛ǖ馈?/em>

在我使用的所有 Go 代碼中,我可以用一只手?jǐn)?shù)出有多少次通道真的是最好的選擇。有時候是這樣的。那很好!那就用它們吧。但除此之外,就不要再使用了。 

責(zé)任編輯:龐桂玉 來源: Linux中國
相關(guān)推薦

2018-12-29 14:45:34

RESTfulGoogleUser

2018-01-17 22:17:16

IT架構(gòu)數(shù)據(jù)糟糕架構(gòu)

2012-07-16 11:27:08

項(xiàng)目開發(fā)

2012-07-16 09:41:59

項(xiàng)目

2021-11-26 22:14:55

PHP編程語言開發(fā)

2022-09-14 09:37:17

JavaScript默認(rèn)導(dǎo)出

2013-06-21 14:02:19

軟件開發(fā)方法

2009-12-09 09:48:23

IT市場失敗事件

2023-01-05 08:34:48

JDK工具

2009-08-24 09:20:18

2021-08-02 08:21:53

Python編程語言開發(fā)

2025-10-20 08:48:00

2020-06-03 15:28:11

QQ新模式簡潔

2012-12-28 09:47:07

程序員代碼編程

2013-09-05 10:33:09

福布斯微軟諾基亞

2013-10-23 10:51:48

開發(fā)模型軟件開發(fā)軟件產(chǎn)業(yè)

2021-10-15 10:24:04

Windows 11操作系統(tǒng)微軟

2018-02-25 11:00:34

代碼開發(fā)程序員

2022-01-17 19:00:28

LinuxWindows微軟

2011-08-05 17:11:42

Amazon
點(diǎn)贊
收藏

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

国产女主播一区| 亚洲手机视频| 日韩三级在线观看| 国产精品第三页| 国产欧美一区二区三区在线看蜜臀| 日韩一区二区三区在线看| 欧美老女人性生活视频| 欧美一区二区三区艳史| www.66久久| 国产极品人妖在线观看| 三日本三级少妇三级99| 一级片免费在线播放| 午夜精品毛片| 日韩大陆毛片av| 天堂中文av在线| 中文av在线全新| 成人免费小视频| 免费国产一区二区| 精品久久无码中文字幕| 久久激情网站| 欧美精品电影在线| 制服丨自拍丨欧美丨动漫丨| 国产调教精品| 91精品国产乱| 国产性生交xxxxx免费| xxx性欧美| 专区另类欧美日韩| 欧美精品欧美精品系列c| www.香蕉视频| 精品一区免费av| 国产成人亚洲综合| 国产无遮无挡120秒| 91成人观看| 在线观看国产精品日韩av| 午夜av免费看| swag国产精品一区二区| 91精品国产91热久久久做人人| 动漫av网站免费观看| 人人超在线公开视频| 国产精品久久二区二区| 日韩动漫在线观看| 天堂视频中文在线| 99精品欧美一区| 亚洲精品一区二区三区在线| 国产尤物视频在线观看| 亚洲色精品三区二区一区| 久久久免费在线观看| 国产精品天干天干在线综合| 人人网欧美视频| 国产精品嫩草影院精东| 日韩欧美不卡视频| 亚洲高清黄色| 一本一道综合狠狠老| www精品久久| 美女日批视频在线观看| 亚洲最大成人综合| 国产精品一色哟哟| 9999在线视频| 欧美日韩激情视频| 久久精品香蕉视频| av在线不卡精品| 欧美日韩一区 二区 三区 久久精品| 黑鬼大战白妞高潮喷白浆| 亚洲欧美小说色综合小说一区| 五月婷婷综合激情| 国产91对白刺激露脸在线观看| 日本在线影院| 国产亚洲电影| 日韩视频三区| 久久久久久香蕉网| 伊人久久综合视频| 国产日韩欧美高清免费| 日韩av理论片| 亚洲视频一区在线播放| 极品少妇xxxx精品少妇偷拍| 69174成人网| 天天操天天插天天射| 91天堂素人约啪| 日韩精品av一区二区三区| 久久天天躁狠狠躁夜夜av| 一区二区不卡在线播放| 欧美二区视频| 欧美大胆a人体大胆做受| 中文字幕高清在线免费播放| 亚洲欧美手机在线| 九九久久99| 日韩中文字幕在线视频| 久久免费99精品久久久久久| 精品一二三区视频| 中文字幕精品—区二区四季| 国产精品8888| 美女露胸视频在线观看| 欧洲生活片亚洲生活在线观看| 国产原创精品在线| 97品白浆高清久久久久久| 亚洲精品久久久一区二区三区 | 亚洲七七久久综合桃花剧情介绍| 亚洲一区二区三区爽爽爽爽爽 | 日韩av在线网站| 欧美三级视频网站| 欧美日韩ab| 国产va免费精品高清在线| 国产剧情精品在线| 久久只精品国产| 精品一区二区成人免费视频 | 无码国产精品久久一区免费| 天堂成人娱乐在线视频免费播放网站 | 欧美日韩中文不卡| 国产精品99久久免费观看| 一区二区三欧美| 国产精品成人久久| 久久精品国产99| 欧美精品成人一区二区在线观看| av中文字幕在线播放| 欧美香蕉大胸在线视频观看| 国产一区二区日韩精品欧美精品| 欧美伊人久久| 日韩免费小视频| 极品白浆推特女神在线观看 | 欧美精品成人久久| 亚洲AV无码精品色毛片浪潮| 成人av中文字幕| 亚洲精品一区二区毛豆| 超级白嫩亚洲国产第一| 91精品婷婷国产综合久久| 中文字幕第4页| 最新日韩欧美| 成人区精品一区二区| 日本中文字幕在线观看| 国产三级在线免费| 国产欧美一区二区精品忘忧草| 男人草女人视频| 日韩av黄色| 国产一区二区三区在线免费观看 | 亚洲精品高清在线| 成人三级视频在线播放| 欧美色图12p| 国产成人午夜视频网址| 蜜臀av午夜精品| 最新欧美精品一区二区三区| 日韩av播放器| 一个色免费成人影院| 欧美精品成人91久久久久久久| 国产喷水福利在线视频| 中文字幕亚洲不卡| 国产无遮挡猛进猛出免费软件| 国产精品一国产精品| 日本国产欧美一区二区三区| 美女欧美视频在线观看免费| 亚洲国产视频一区二区| 亚洲精品乱码久久久久久9色| 欧美hd在线| 国产免费一区二区三区香蕉精| 北岛玲一区二区三区| 日本道免费精品一区二区三区| 国产肉体xxxx裸体784大胆| 91久久在线| 大地资源网在线观看免费官网| 国产精品99精品无码视亚| 九一精品国产| 国产精品av在线| 99中文字幕一区| 欧美日韩国产a| 精品无码一区二区三区蜜臀| 国产精品一区三区| www.九色.com| 久久亚洲黄色| 日本欧美中文字幕| seseavlu视频在线| 6080午夜不卡| 久久精品波多野结衣| 成人激情免费网站| 91看片就是不一样| 日韩在线综合| 国产精品xxxx| 日本一区免费网站| 久久久精品999| 亚洲h视频在线观看| 欧美午夜片欧美片在线观看| 国产无遮挡在线观看| 国产风韵犹存在线视精品| 久草热视频在线观看| 91欧美在线| 精品国产乱码一区二区三区四区 | 午夜免费福利视频在线观看| 亚洲综合自拍| 欧美日韩一区二区三区在线观看免 | 亚洲午夜久久久久中文字幕久| 成人乱码一区二区三区av| 国产真实乱对白精彩久久| 免费无码不卡视频在线观看| 91亚洲成人| 欧美高清视频一区| 日韩欧美高清一区二区三区| 日本在线精品视频| 亚洲制服国产| 亚洲欧洲中文天堂| 国产成人aa精品一区在线播放| 99热这里只有精品3| 狠狠躁夜夜躁久久躁别揉| 性の欲びの女javhd| 久久99精品国产麻豆婷婷洗澡| 农民人伦一区二区三区| 欧美欧美黄在线二区| 91九色国产社区在线观看| 男女在线视频| 亚洲人成在线观看网站高清| 国产精品一区二区免费视频| 欧美日韩精品二区| 黄色在线观看免费| 久久久精品国产免大香伊| 亚洲成人手机在线观看| 久久av最新网址| www.在线观看av| 日本久久黄色| 精品不卡在线| 欧美2区3区4区| 国产伦精品免费视频| 成人ssswww在线播放| 乱亲女秽乱长久久久| 国产在线一在线二| 亚洲成人av中文字幕| 欧美一区免费看| 亚洲一区二区四区蜜桃| 蜜桃av免费在线观看| 久久九九99视频| www国产视频| 国产精品99久久久久久有的能看| 天天色综合天天色| 国产精品亚洲欧美| 欧美a级免费视频| 99久久99热这里只有精品 | 性生活免费网站| 欧美色爱综合网| www.com亚洲| 午夜激情久久久| 国产91av视频| 亚洲老司机在线| 来吧亚洲综合网| 久久久精品黄色| 中文字字幕码一二三区| 国产一区二区在线免费观看| 色婷婷成人在线| 日韩av不卡在线观看| 亚洲人成色77777| 另类激情亚洲| 精品www久久久久奶水| 国产九九精品| 91视频最新入口| 国产日韩免费| 国产在线青青草| 日韩精品每日更新| 成年人在线看片| 另类图片国产| 岛国毛片在线播放| 蜜桃在线一区二区三区| 天天操天天爽天天射| 亚洲人体大胆视频| 欧美黄网站在线观看| 国产视频一区欧美| 99热在线这里只有精品| 久久精品官网| av丝袜天堂网| 蜜桃91丨九色丨蝌蚪91桃色| 亚洲少妇久久久| 国产美女精品在线| 亚洲熟妇一区二区| 成人免费毛片片v| 亚洲综合色一区| 国产亚洲精久久久久久| 午夜时刻免费入口| 日本一区二区综合亚洲| 黑人狂躁日本娇小| 亚洲欧美成aⅴ人在线观看| 黄视频网站免费看| 无吗不卡中文字幕| 天堂网视频在线| 欧美午夜宅男影院| 中文字幕人妻互换av久久| 6080yy午夜一二三区久久| 国产成人a人亚洲精品无码| 日韩欧美中文字幕制服| 欧美孕妇性xxxⅹ精品hd| 亚洲日本欧美日韩高观看| 日韩av中文| 欧美激情一区二区久久久| 久久人体大尺度| 国产美女精品视频免费观看| 久久wwww| 日韩av电影免费观看| 99视频精品全国免费| 成人免费看片'免费看| 日韩国产在线观看一区| 一级黄色高清视频| 91在线观看视频| 亚洲一二三精品| 亚洲va韩国va欧美va| 老熟妇一区二区三区啪啪| 717成人午夜免费福利电影| 天堂а√在线8种子蜜桃视频| 色av吧综合网| jizzjizz中国精品麻豆| 成人免费视频网址| 久久久亚洲欧洲日产| 亚洲精品久久区二区三区蜜桃臀| 一区二区三区福利| 成人性生交免费看| 成人短视频下载| 永久免费看片直接| 精品国产乱码久久久久久虫虫漫画| 中文字幕二区三区| 精品国精品国产| 色综合久久影院| 国产91精品久久久| 91精品国产自产观看在线| www久久99| 九九视频免费观看视频精品| 久久手机在线视频| 国产一区二区看久久| 中国黄色a级片| 一区二区三区免费在线观看| 中文字幕自拍偷拍| 亚洲美女av在线播放| 亚洲第一图区| 91久久国产精品91久久性色| 国产免费播放一区二区| 国产原创popny丨九色| 高清不卡一二三区| 国产男女猛烈无遮挡在线喷水| 色偷偷成人一区二区三区91| 欧美一级做性受免费大片免费| 久久精品久久久久久国产 免费| 一级毛片久久久| 成人av播放| 91精品二区| 五月天av在线播放| 国产精品视频看| 91黑人精品一区二区三区| 日韩精品极品视频免费观看| 蜜桃av在线| 国产精品毛片va一区二区三区| 欧美不卡视频| 亚洲国产精品狼友在线观看| 亚洲欧美精品午睡沙发| 一区二区不卡视频在线观看| 久久久国产精彩视频美女艺术照福利 | 国产一区在线电影| 少妇大叫太大太粗太爽了a片小说| 国产精品一卡二卡| 免费无码毛片一区二区app| 在线成人午夜影院| 91ph在线| 国产精品亚洲片夜色在线| 欧美手机在线| 亚洲成人av免费看| 中文字幕亚洲欧美在线不卡| 亚洲系列第一页| 日韩中文字幕在线看| 欧美第一在线视频| 视色,视色影院,视色影库,视色网| 蜜桃视频一区二区三区| www.av成人| 欧美一区二区三区性视频| 在线观看男女av免费网址| 亚洲999一在线观看www| 欧美一区综合| 亚洲av网址在线| 色综合天天综合狠狠| 高清av在线| 91视频99| 亚洲精品社区| 日本激情小视频| 欧美美女喷水视频| 欧美巨大xxxx做受沙滩| 九九热久久66| 日本aⅴ免费视频一区二区三区| 男女男精品视频网站| 精品久久一区二区三区| 国产乱码午夜在线视频| 久久久久久高清| 精品一区二区三区在线观看| 91九色丨porny丨极品女神| 日韩一区和二区| 亚洲校园激情春色| 亚洲精蜜桃久在线| 丁香网亚洲国际| 无码人妻久久一区二区三区不卡| 深夜福利亚洲导航| 成人激情自拍| www.超碰com| 一区二区高清视频在线观看| 国产在线网站| 91在线观看欧美日韩| 久久99伊人| 亚洲一级生活片| 精品亚洲一区二区三区在线观看| 豆花视频一区| 欧美成人高潮一二区在线看| 国产精品美女久久久久久久网站| 东京干手机福利视频|