到目前為止,我描繪了一個非常嚴酷的場景。 并發在計算機科學中當然是一個困難的領域,但我希望你不要失去希望:這些問題不是無解的,使用Go的并發原語,可以更安全,更清晰地表達并發算法。 我們討論的運行時長和溝通困難并不是Go能夠完全解決的,但它們確實變得更加容易處理了。在這里,我們花一點時間來探索Go的并發原語,以助于更容易地對問題域進行建模,并更清楚地表達算法。
Go的運行時完成了大部分繁重的工作,并為Go的大部分并發優勢提供了基礎。詳細部分我們放到第6章再講,但現在讓我們討論下它是如何讓人生變得輕松的。
我們先看看Go的并發,低延遲,自動執行垃圾收集器(GC)。開發者經常討論GC是否是語言中必備的東西。批評者認為,GC阻止任何需要實時性能或確定性能特征的問題領域的工作——暫停程序中的所有活動來清理垃圾簡直是不可接受的。但Go的GC所做的出色工作大大減少了開發者的心智負擔。從Go 1.8開始,垃圾收集暫停一般在10到100微秒之間。
這對你有什么幫助? 內存管理可能是計算機科學領域的另一個難題,如果與并發性結合使用,編寫正確的代碼變得非常困難。如果大多數開發人員不需要擔心低至10微秒的暫停時間,那么Go通過不強迫你管理內存而更容易使用并發程序,更不用說跨并發進程了。
Go的運行時也會自動處理并發操作到操作系統線程上。這么說有些籠統,我們將在第三章的“Goroutines”一節中確切地說明這意味著什么。為了理解這對開發者的幫助,你需要知道的一點是它允許開發者直接將并發問題映射到結構體,而不是處理啟動和管理線程的細節,并在可用線程間均勻映射邏輯。
例如,假設你編寫了一個Web服務器,并且你希望每個連接都可以與其他連接同時處理。 在某些語言中,在Web服務器開始接受連接之前,你可能必須創建一個線程集合(通常稱為線程池),然后將傳入連接映射到線程。 然后,在你創建的每個線程中,你需要循環該線程上的所有連接,以確保它們都獲得了一些CPU時間。 另外,你必須編寫你的連接處理邏輯,使它可以與其他連接公平地共享。
相比之下,在Go中你可以編寫一個函數,然后用go關鍵字預先調用它。 運行時會處理我們自動調用的所有內容! 當你正在經歷設計程序的過程時,你認為在哪種模型下你更有可能達到預期的并發效果? 你認為哪個更可能是正確的?
Go的并發原語也使得解決更大的問題變得更容易。 正如我們將在第三章的“Channels”部分中看到的,Go的channel原語為并發進程之間的通信提供了可組合,并發安全的方式。
我已經掩蓋了大部分細節,但我想給闡述一些關于Go如何在程序中處理并發,以幫助你以清晰和高效的方式解決問題。 這將是下一張的內容。 如果渴望立刻開始討論代碼,你可能會想轉到第三章。
* * * * *
學識淺薄,錯誤在所難免。我是長風,歡迎來Golang中國的群(211938256)就本書提出修改意見。
- 前序
- 誰適合讀這本書
- 章節導讀
- 在線資源
- 第一章 并發編程介紹
- 摩爾定律,可伸縮網絡和我們所處的困境
- 為什么并發編程如此困難
- 數據競爭
- 原子性
- 內存訪問同步
- 死鎖,活鎖和鎖的饑餓問題
- 死鎖
- 活鎖
- 饑餓
- 并發安全性
- 優雅的面對復雜性
- 第二章 代碼建模:序列化交互處理
- 并發與并行
- 什么是CSP
- CSP在Go中的衍生物
- Go的并發哲學
- 第三章 Go的并發構建模塊
- Goroutines
- sync包
- WaitGroup
- Mutex和RWMutex
- Cond
- Once
- Pool
- Channels
- select語句
- GOMAXPROCS
- 結論
- 第四章 Go的并發編程范式
- 訪問范圍約束
- fo-select循環
- 防止Goroutine泄漏
- or-channel
- 錯誤處理
- 管道
- 構建管道的最佳實踐
- 便利的生成器
- 扇入扇出
- or-done-channel
- tee-channel
- bridge-channel
- 隊列
- context包
- 小結
- 第五章 可伸縮并發設計
- 錯誤傳遞
- 超時和取消
- 心跳
- 請求并發復制處理
- 速率限制
- Goroutines異常行為修復
- 本章小結
- 第六章 Goroutines和Go運行時
- 任務調度