談談Go併發編程

一、前言

Go語言在設計時,Java和C ++是編寫服務器程序最常用的語言(至少在Google是這樣),這是因爲使用這些語言可以高效的開發。但是Go設計者們覺得像Java和C++這些語言需要開發者記憶太多的語法和規則,並且需要重複做的事情太多,這導致一些程序員開始轉向更加動態,流暢的語言,如Python,但是付出的是損失開發效率和對類型安全檢查的缺失。Go設計者們認爲應該可以發明一種語言,這種語言集高效的開發、提供類型安全檢查、簡潔流暢的代碼風格與一體,於是Go就誕生了。

二、GoLang併發編程

Go在語言層面提供了內置的併發支持,在Google內部運行在多核心cpu機器之上並擁有高併發流量的web服務器程序,是最典型應用。由於C++和Java在語言層面對併發的支持不是特別好,所以使用它們編寫高併發程序都不是特別容易。

傳統的線程模型,比如經常使用Java、C++、Python編程的時候,需要多個線程之間通過共享內存(比如在堆上創建的共享變量)來通信。這時候爲保證線程安全,多線程共享的數據結構需要使用鎖來保護,多線程訪問共享數據結構時候需要競爭獲取鎖,只有獲取到鎖的線程纔可以存取共享數據。

Go中也提供了這種低級同步原語-鎖,比如互斥鎖、讀寫鎖、條件變量等,但是Go的併發原語 - goroutines和channels 提供了一種優雅而獨特的結構化開發併發軟件的方式。 Go鼓勵使用通道在goroutine之間傳遞對共享數據的引用,而不是明確地使用鎖來保護對共享數據的訪問。 這種方法確保在給定時間只有一個goroutine可以訪問共享數據。 這個理念被總結爲:不要通過共享內存來通信,而要通過通信來共享內存。

Go中併發模型採用了channel,體現爲CSP的一個變種。之所以選擇CSP,一方面是因爲Google的開發工程師對它的熟悉程度,一方面因爲CSP具有一種在無須對其模型做任何深入的改變就能輕易添加到過程性編程模型中的特性。比如,對於C語言,CSP可以一種最長正交化(orthogonal)的方式添加到這種語言中,爲該語言提供額外的表達能力而且還不會對該語言的特性施加任何約束。

在其他語言比如Java中線程模型的實現是一個操作系統內核線程對應着一個我們使用new Thread創建的一個線程,而由於操作系統線程個數是有限制的,所以限制了我們創建的線程個數,另外當線程執行阻塞操作時候,線程要從用戶態切換到內核態執行,這個開銷是比較大的;而在golang中線程模型則是一個操作系統線程對應多個goroutine,用戶可以創建goroutine個數只受內存大小限制,另外上下文切換髮生在用戶態,切換速度比較快,並且開銷比較小,所以go中一臺機器可以創建百萬的goroutine。

在Java中當我們編寫併發程序時候我們需要在操作系統線程層面進行考慮,但是在go中,我們不需要考慮操作系統線程,而是需要站在goroutine和channel上進行思考,當然有時候也會在共享內存上進行思考。

另外大家或許聽說過反應式編程、反壓等概念,比如Java中rxjava庫提供的功能,而在go中我們可以使用channel輕易的實現管道,讓多個goroutine進行任務進行fork然後進行join,以及輕易的實現反壓功能。

Golang的應用範圍越來越廣,大名鼎鼎的容器化技術docker以及號稱分佈式操作系統的k8s底層實現就是Golang來實現的,隨着技術的快速發展,我們只有不斷迭代自己的技術棧,才能不會被淘汰,而golang將會是未來應用場景比較多的一種語言,各大公司也將會要求必須掌握golang來進行快速開發高併發應用程序。

最後推薦《Go併發編程之美》 專題,該專題從下向上,基礎篇首先會基於數據競爭的存在、內存訪問需要同步、原子變量、講解併發編程到底難在哪裏,然後講解Go的線程模型、內存模型、goroutine的基礎知識;然後深入講解Go中提供的低級同步原語鎖,以及鎖的內存模型;接着講解Go獨特的同步原語channel,以及channel的內存模型,以及channel、goroutine、select的結合使用;然後講解go中的Context包,我們會展開講解如何傳遞請求級別的變量、如何使用context在一個goroutine內取消另外一個goroutine的運行;相信學完本專欄,大家對go併發編程會有深入的理解,並會爲go中併發編程精髓channel、select、goroutine的搭配功能而驚豔到。

最後大家可以掃描參加該課程的學習:
基礎篇:
image.png

低級同步原語:鎖
image.png

高級同步原語:通道
image.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章