串行和并行的区别_入门参考:从Go中的协程理解串行和并行
本文轉自公眾號語言隨筆,歡迎關注
入門參考:從Go中的協程理解串行和并行?mp.weixin.qq.comGo語言的設計亮點之一就是原生實現了協程,并優化了協程的使用方式。使得用Go來處理高并發問題變得更加簡單。今天我們來看一下Go中的協程。
從串行到并行
在處理器還是單個單核的時候,這個時候并不存在并行,因為只有一個處理器。所以那時候的編程都是串行編程。程序執行都是從頭順序執行到尾。到了多處理器多核的時代,為了充分利用處理器的處理能力,開始出現了并發編程。開發者開始在進程中啟用多個線程來執行操作,利用CPU的調度能力來最大化程序處理效率。
并發,并行
在說到并發編程的時候總會遇到這兩個概念,面試的時候也會問道,在這里就簡單說一下這兩者的區別:
并發是一種能力,是指多個任務在一段時間內同時發生。 并行值得是多個任務同時發生,就是并行。并發值得是并行的能力,并發不一定是同時發生,可能是同一時間段內交替發生。
進程,線程,協程
進程和線程是操作系統的基本概念:
進程:指計算機中已運行的程序,進程是程序的基本執行實體。 線程:是操作系統能夠進行運算調度的最小單位。它被包含在進程中,是進程的實際運行單位。那么協程是在線程之上,更加輕量級的設計。協程因為只工作在用戶控件,沒有線程上下文切換帶來的消耗。協程的調度由用戶手動切換,所以更加靈活。
協程的另一大優勢就是因為在用戶空間調度,所以不會出現代碼執行一半被強制中斷,所以無需原子操作鎖。
Go中的協程
在Go中使用協程非常簡單,就使用go關鍵字就可以了。我們來看一段串行代碼使用協程如何進行操作:
package mainimport ("fmt""time" )func main(){print1To10() }func print1To10(){for i := 1; i<=10; i++{fmt.Printf("%d ", i)} }// 輸出 // 1 2 3 4 5 6 7 8 9 10那么使用協程,我們來看一下運行結果:
package mainimport ("fmt""time" )func main(){fmt.Println("before go coroutine")go print1To10()fmt.Println("after go coroutine")time.Sleep(100 * time.Millisecond) //防止主協程直接結束了,打印協程還沒來得及執行 }func print1To10(){for i := 1; i<=10; i++{fmt.Printf("%d ", i)} }// 輸出 /*********** before go coroutine after go coroutine 1 2 3 4 5 6 7 8 9 10 *************/我們可以看出使用go關鍵詞后,打印并不是按照順序串行執行的,而是在主協程執行結束后,打印協程才開始執行。
Go協程的調度機制
Go中的協程調度模型是G-P-M模型:
G代表Goroutine,也就是Go中的協程對象。 P代表Processor,代表虛擬的處理器。一般來說,和邏輯核一一對應。 M代表Machine,實際上是操作系統的線程。這里我們簡單說一下Go的調度機制,感興趣或者有了解的可以自行看Go的源碼:
其中第4條 盡可能獲取G 則是Go的有趣的設計理念之一,當一個 P 發現自己的 LRQ 已經沒有 G 時,會從其他 P “偷” 一些 G 來運行。看看這是什么精神!自己的工作做完了,為了全局的利益,主動為別人分擔。這被稱為 Work-stealing。
再看串行和并行
這里我們以Go協程來繼續說一下串行和并行,對于習慣于串行編程的程序員來說,理解并行可能稍微需要點時間,對于程序設計來說,并行的設計主要是為了提高程序運行的效率,使得程序能夠充分利用多核多處理器的資源(或者多機器)。那么對于如何充分利用,大部分支持并行編程的語言都有其內部的調度機制,即使沒有,也會使用系統的調度機制--線程調度。
那么對于并行調度機制總體上分為兩類:協作式和搶占式
協作式:一個任務得到了 CPU 時間,除非它自己放棄使用 CPU ,否則將完全霸占 CPU ,所以任務之間需要協作使用一段時間的 CPU ,放棄使用,其它的任務也如此,才能保證系統的正常運行。如果有一個任務死鎖,則系統也同樣死鎖。搶占式:總控制權在操作系統手中,操作系統會輪流詢問每一個任務是否需要使用 CPU ,需要使用的話就讓它用,不過在一定時間后,操作系統會剝奪當前任務的 CPU 使用權,把它排在詢問隊列的最后,再去詢問下一個任務。如果有一個任務死鎖,系統仍能正常運行。
在 Go1.1 版本中,調度器還不支持搶占式調度,只能依靠 goroutine 主動讓出 CPU 資源,存在非常嚴重的調度問題。
Go1.12 中編譯器在特定時機插入函數,通過函數調用作為入口觸發搶占,實現了協作式的搶占式調度。但是這種需要函數調用主動配合的調度方式存在一些邊緣情況。
后面Go在1.14版本實現了基于信號的真搶占式調度。用于解決解決了垃圾回收和棧掃描時存在的問題。
Go的協程調度目前雖然不能稱得上完美,但是對于我們理解并行有一定的幫助。所謂并行編程,就是開啟多個任務而不用等待任務結果。可以使得相互獨立的任務同時運行,比如文件寫入等。
總結
以上是生活随笔為你收集整理的串行和并行的区别_入门参考:从Go中的协程理解串行和并行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 下划线转驼峰_json字符
- 下一篇: mro python_用python实现