精品欧美一区二区三区在线观看 _久久久久国色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ù)棧公眾號

久久999免费视频| 4438x亚洲最大成人网| 免费看成人av| 国产精品午夜一区二区| 欧美激情第二页| 日韩av在线免播放器| 成人免费视频久久| 欧美四级在线| 国产人成亚洲第一网站在线播放| 国产精品一区二区三| www.99re7.com| 第四色成人网| 亚洲国模精品一区| 亚洲一区二区福利视频| 成年女人在线看片| 亚洲欧洲www| 欧美精品一区二区三区四区五区| 国产深喉视频一区二区| 男人的天堂亚洲| 欧美区二区三区| 99在线视频免费| 精品无人区一区二区| 欧美日韩第一区日日骚| 岳毛多又紧做起爽| 国产蜜臀一区二区打屁股调教| 国产午夜亚洲精品理论片色戒 | 中文字幕一区图| 欧美撒尿777hd撒尿| 黄色网页免费在线观看| 影院在线观看全集免费观看| 国产欧美日韩精品a在线观看| 国产一级特黄a大片99| 国内老熟妇对白hdxxxx| 久久精品国产99| 日本乱人伦a精品| 日韩成人高清视频| 韩日在线一区| 久久久精品在线观看| 国产在线免费av| 欧美美女在线| 日韩精品一区二区三区第95| 俄罗斯黄色录像| 99久久人爽人人添人人澡| 欧美精品一级二级三级| 国产九九在线视频| 精品肉辣文txt下载| 欧美性猛交xxxx富婆| 老太脱裤让老头玩ⅹxxxx| 免费在线中文字幕| 亚洲午夜久久久久久久久久久| 最新视频 - x88av| 成人影院在线看| 亚洲色欲色欲www在线观看| 亚洲乱码一区二区三区| √天堂资源地址在线官网| 国产欧美精品区一区二区三区| 欧美一区观看| 992tv免费直播在线观看| 欧美国产日韩精品免费观看| 神马影院我不卡| av中文字幕一区二区三区| 国产精品欧美综合在线| 亚洲精品一品区二品区三品区 | www男人的天堂| 国产成人午夜精品5599| 高清视频一区| 天堂v在线观看| 久久新电视剧免费观看| 日韩视频在线观看国产| 日本在线免费播放| 亚洲精品精品亚洲| 男人添女人荫蒂免费视频| 蜜臀久久精品| 欧美午夜精品免费| 天堂网成人在线| 亚洲一区电影| 日韩高清av一区二区三区| 国产全是老熟女太爽了| 日韩www.| 国模精品视频一区二区| 国产乡下妇女做爰毛片| 日韩 欧美一区二区三区| 国产区精品视频| 成人免费视频国产免费麻豆| 26uuu国产电影一区二区| 午夜精品一区二区三区在线观看 | 亚洲欧美日韩中文字幕一区二区三区| 亚洲天堂第一区| 色黄视频在线观看| 欧美日韩成人高清| 国产艳妇疯狂做爰视频| 加勒比久久综合| 欧美丰满少妇xxxxx| 在线观看日本网站| 国产乱子轮精品视频| 久久久www免费人成黑人精品| 在线观看国产原创自拍视频| 亚洲高清免费观看高清完整版在线观看 | 白白色免费视频| 国产精品嫩模av在线| xvideos成人免费中文版| 69精品久久久| 美女尤物国产一区| 国产精品视频一区二区三区经| 第九色区av在线| 亚洲午夜三级在线| wwwwwxxxx日本| 加勒比中文字幕精品| 色婷婷av一区二区三区久久| 97人人澡人人爽人人模亚洲| 美女视频网站黄色亚洲| 国产一区在线免费| 日本福利在线| 色偷偷久久一区二区三区| 不卡的一区二区| 久久中文亚洲字幕| 欧美一级大片视频| 国产综合在线播放| 综合中文字幕亚洲| 免费看污污网站| 日韩av三区| 欧美激情中文字幕在线| 亚洲图片欧美在线| 久久久国际精品| 国产精品久久中文字幕| 一区二区亚洲视频| 久久综合五月天| 在线观看日韩一区二区| 久久久另类综合| 天堂…中文在线最新版在线| 亚洲三级av| 久久成人18免费网站| 在线观看免费黄色小视频| 久久精品夜色噜噜亚洲a∨| 日韩精品 欧美| 中文字幕久久精品一区二区| 欧美成人合集magnet| 亚洲综合精品在线| 中文字幕中文字幕一区| 国产精品区在线| 成人网18免费网站| 国产精品偷伦免费视频观看的| 欧美色图另类| 色婷婷av一区二区三区大白胸 | 国产精品久线观看视频| 天天综合网日韩| 日韩欧美视频在线播放| 国产精品久久9| av午夜在线| 欧美精品 日韩| 免费看特级毛片| 国产综合色在线视频区| 欧美日韩亚洲国产成人| 国产剧情一区二区在线观看| 超碰日本道色综合久久综合| 国产女人18毛片水真多| 亚洲蜜臀av乱码久久精品 | 久久av偷拍| 欧美美女操人视频| 亚洲av少妇一区二区在线观看| 亚洲五码中文字幕| 粉嫩av懂色av蜜臀av分享| 老鸭窝91久久精品色噜噜导演| 欧美xxxx黑人又粗又长密月 | 在线观看三级视频欧美| 2019男人天堂| 国产最新精品免费| av网站手机在线观看| 色婷婷精品视频| 国产精品福利在线观看| dy888亚洲精品一区二区三区| 欧美大片一区二区三区| 91美女免费看| 国产精品久久久久影院老司| 操人视频免费看| 99国产一区| 亚洲国产一区二区三区在线| 国产激情综合| 91大神在线播放精品| a√资源在线| 欧美成人bangbros| 青青视频在线免费观看| 成人欧美一区二区三区在线播放| 九九久久久久久| 亚洲一区欧美二区| 亚洲午夜精品久久| 国产精品tv| 国产精品国产自产拍高清av水多| 成人福利片网站| 日韩国产高清视频在线| 亚洲专区第一页| 欧美日韩激情美女| 黄视频网站免费看| 91蜜桃视频在线| 黄色片子免费看| 亚洲男女自偷自拍| 国产在线拍揄自揄拍无码| 网友自拍一区| 69174成人网| 日韩久久一区二区三区| 精品中文字幕在线| 91福利在线视频| 日韩av在线网址| 国产欧美第一页| 在线视频一区二区三| 久久久一区二区三区四区| 亚洲国产成人私人影院tom| 88av在线播放| 国产麻豆精品视频| 三级在线免费看| 国产人成精品一区二区三| 警花观音坐莲激情销魂小说| 精品国产不卡| 99r国产精品视频| 亚洲伦理一区二区| 国产精品久久久久久久久影视| av美女在线观看| 欧美久久久精品| 1769在线观看| 国产一区二区三区三区在线观看| 无码h黄肉3d动漫在线观看| 制服.丝袜.亚洲.另类.中文 | 日本欧美韩国一区三区| 国产资源在线视频| 亚洲视频免费| 成人午夜视频免费观看| 欧美电影免费| 亚洲精品一区二区毛豆| 精品日韩在线| 日本一区二区不卡高清更新| 日韩精品丝袜美腿| 狠狠色伊人亚洲综合网站色| www.亚洲一二| 国产精品乱子乱xxxx| 日韩欧美高清一区二区三区| 成人免费激情视频| 狂野欧美性猛交xxxx| 国产精品视频播放| 欧美videos粗暴| 日韩av片免费在线观看| 日本免费一区二区三区四区| 18性欧美xxxⅹ性满足| 51精品视频| **欧美日韩vr在线| 中文在线最新版地址| 欧美综合在线第二页| 欧美xxx视频| 国产精品xxxxx| 成人国产综合| 国产有码在线一区二区视频| 99精品女人在线观看免费视频| 国产日产欧美a一级在线| 亚洲精品777| 亚洲精品欧美极品| 99re8这里有精品热视频8在线| aaa级精品久久久国产片| 91国内精品| 精品高清视频| 国产伦一区二区三区| 少妇精品久久久久久久久久| 久久中文字幕av一区二区不卡| 中文字幕一区二区三区四区五区人| 97精品国产一区二区三区| 中文字幕一区二区三区在线乱码| 一区二区三区在线电影| aa视频在线播放| 午夜在线a亚洲v天堂网2018| 久草福利视频在线| 国内精品久久久久影院色| 高清中文字幕mv的电影| 91老司机福利 在线| www久久久久久久| 亚洲欧美色一区| 国产精品老女人| 欧美三级视频在线| www.日本在线观看| 精品伊人久久97| 麻豆视频免费在线观看| 国内精品久久影院| 欧美va在线| 99re国产在线播放| 亚洲综合小说图片| 妞干网这里只有精品| 99在线精品免费视频九九视| 91日韩视频在线观看| 国产精品主播直播| 9.1成人看片免费版| 亚洲图片你懂的| 国产三级av片| 制服丝袜中文字幕一区| 男女污污视频在线观看| 久久久精品国产亚洲| 亚洲欧美韩国| 91精品国产一区二区三区动漫| 亚洲国产国产| 亚洲免费视频播放| 久久先锋资源| 不许穿内裤随时挨c调教h苏绵| 国产校园另类小说区| 国产极品在线播放| 欧美日韩免费高清一区色橹橹| 欧美熟女一区二区| 日韩亚洲欧美成人| 欧美香蕉视频| 国产福利一区二区三区在线观看| 欧美精品一区二区三区精品| 丰满的少妇愉情hd高清果冻传媒| 蜜臀av一区二区在线观看| 大尺度做爰床戏呻吟舒畅| 中文字幕一区在线观看| 久久亚洲天堂网| 亚洲成年人在线播放| 免费的黄网站在线观看| 国产99在线|中文| 丁香五月缴情综合网| 免费观看中文字幕| 久久国产精品72免费观看| 在线观看国产精品一区| 午夜精品久久久久久久久久| 国产丝袜视频在线观看| 日韩在线视频二区| 欧美日韩电影免费看| 国产精品亚洲一区| 午夜日韩电影| 一级 黄 色 片一| 中文字幕巨乱亚洲| 欧美brazzers| 亚洲精品有码在线| 色吧亚洲日本| 久久av一区二区三区漫画| 激情欧美日韩| 超碰caoprom| 亚洲午夜日本在线观看| 丁香六月天婷婷| 欧美片一区二区三区| 日韩中文字幕一区二区高清99| a级网站在线观看| 精品系列免费在线观看| 懂色av蜜臀av粉嫩av永久| 欧美日韩免费一区二区三区| 91xxx在线观看| 成人黄色av播放免费| 亚洲精品久久久| 欧美污在线观看| 一区二区三区精品| av中文字幕免费在线观看| 欧美成人免费大片| 亚洲午夜免费| 秋霞无码一区二区| 91香蕉国产在线观看软件| 91精品国产乱码久久久张津瑜| 亚洲国产精品一区二区久| 日韩精品av| 日韩中文一区二区三区| 美女网站色91| 中文乱码字幕高清一区二区| 宅男噜噜噜66一区二区66| 成人免费网站在线观看视频| 国产精品久久一区二区三区| 亚洲美女视频在线免费观看| 97人妻天天摸天天爽天天| 色综合天天综合给合国产| 国产福利免费在线观看| 国产日韩av高清| 国产精品magnet| 西西大胆午夜视频| 色国产综合视频| 久久精品视频免费看| 国产 高清 精品 在线 a| 亚洲制服av| www成人啪啪18软件| 日韩精品专区在线| 中文不卡1区2区3区| 一区二区不卡在线观看| 丁香婷婷综合色啪| 中文字幕免费高清网站| 久久精品99国产精品酒店日本| 97一区二区国产好的精华液| 农村妇女精品一二区| 亚洲日本一区二区| 无码精品在线观看| 国产日本欧美一区二区三区| 亚洲特级毛片| 久久久久久国产免费a片| 欧美一区二区三区免费在线看| 国产理论电影在线 | 久久精品久久久| 人体私拍套图hdxxxx| 欧美色精品在线视频| 密臀av在线| 自拍偷拍99| 91麻豆精东视频| 国产成a人亚洲精v品无码| 人人做人人澡人人爽欧美| 综合国产精品| 精品日韩在线视频| 日韩成人在线网站| 国产中文欧美日韩在线| 国产免费视频传媒| 亚洲va天堂va国产va久|