聊聊並發,進程通訊方式,go協程簡單應用場景
開篇提問
- 知道並發,並行,執行緒,協程概念嗎?或者知道大概含義嗎?
- 有執行緒為什麼還要有協程?區別是什麼?
- 『進程』通訊方式知道幾種?有沒有超過3種?
- golang『協程』通訊方式推薦?
- 使用並發的目的是為什麼?是能幫我們解決什麼問題嗎?
概念
並發,執行緒,協程:概念是不可能概念的,google去吧。或者點擊這裡,查看上一篇文章
- 並行:一般是指多個CPU實例或者多台機器在『同一時刻』同時執行某個邏輯(方法)
『進程』通訊方式
名稱 | 特點 |
---|---|
管道/匿名管道(pipe) | 管道的實質是一個內核緩衝區 |
有名管道(FIFO) | 先進先出(first in first out); 以有名管道的文件形式存在於文件系統中; |
訊號(Signal) | 無需知道該進程的狀態; 阻塞進程; 非同步通訊; |
消息隊列(Message Queue) | 放在內核中的消息鏈表; 允許一個或多個進程向它寫入與讀取消息; 克服了訊號承載資訊量少缺陷; 目前主要有兩種類型的消息隊列:POSIX消息隊列以及System V消息隊列,系統V消息隊列目前被大量使用; |
共享記憶體(share memory) | 使得多個進程可以可以直接讀寫同一塊記憶體空間,是最快的可用IPC形式; 由於多個進程共享一段記憶體,因此需要依靠某種同步機制(如訊號量)來達到進程間的同步及互斥; |
訊號量(semaphore) | 訊號量是一個計數器,用於多進程對共享數據的訪問,訊號量的意圖在於進程間同步只能通過兩個標準原子操作:wait(semap) , signal(semap) ;進行訪問 訊號量是非負整型變數 操作也被成為PV原語(P來源於荷蘭語proberen”測試”,V來源於荷蘭語verhogen”增加”,P表示通過的意思,V表示釋放的意思) |
套接字(socket) | 套接字是支援TCP/IP的網路通訊的基本操作單元 套接字的特性由3個屬性確定,它們分別是:域、埠號、協議類型。 |
訊號量與互斥量之間的區別:
(1)互斥量用於執行緒的互斥,訊號量用於執行緒的同步。這是互斥量和訊號量的根本區別,也就是互斥和同步之間的區別。
互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。
在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源
(2)互斥量值只能為0/1,訊號量值可以為非負整數。
也就是說,一個互斥量只能用於一個資源的互斥訪問,它不能實現多個資源的多執行緒互斥問題。訊號量可以實現多個同類資源的多執行緒互斥和同步。當訊號量為單值訊號量是,也可以完成一個資源的互斥訪問。
(3)互斥量的加鎖和解鎖必須由同一執行緒分別對應使用,訊號量可以由一個執行緒釋放,另一個執行緒得到。
go協程通訊使用
基本上就是推薦使用channel,這個是最推薦的使用形式;
還有就是使用sync.Mutex
互斥鎖進行加鎖通訊;
更詳細的介紹以後寫;
go使用協程一些應用場景,簡單舉例
- 進行互不相干的『循環』,需要等待結果計算
這種情況下,一般是不同『數據集合』需要進行『處理』,在處理的過程中兩個數據集合對『結果』造成的影響沒有時序行;
這種情況下,完全可以採用兩個數據單獨進行協程處理然後再進行後續運算;
// 偽程式碼
var result, data1, data2 int32
done1 := make(chan bool)
done2 := make(chan bool)
// 第一個數據集合,需要求和
go func() {
for _, val := range dataset1 {
data1 += val
}
done1 <- true
}
// 第二個數據集合,需要求和
go func() {
for _, val := range dataset2 {
data2 += val
}
done2 <- true
}
// 等待協程完成運算
<-done1
<-done2
// 結果進行相加
result = data1 + data2
- 需要額外進其他不相干的業務,不耽誤『主協程』的返回值,不等待
一般有些業務處理以後,有些『額外工作』需要處理但是不耽誤主協程返回數據,這個時候就可以開個協程去做,不用等待
// 偽程式碼
result, err := processMethod()
if err != nil {
.....
}
// 需要對結果進行寫快取等其他操作,不耽誤數據返回
go func() {
err = saveRedis(result)
if err != nil {
.....
}
}
return result
- 對某些任務進行時間限制,『超時關閉』當前操作
例如,通過管道channel發送某些數據,若超時則自動放棄本次發送,關閉通道。
// 定義兩個有緩衝通道,容量分別為1
c1 := make(chan string, 1)
c2 := make(chan string, 1)
go func() {
time.Sleep(time.Second * 1) // 隔1秒發送數據
c1 <- "data1"
}()
go func() {
time.Sleep(time.Second * 6) // 隔6秒發送數據
c2 <- "data2"
}()
for i := 0; i < 2; i++ {
// 給通道創建容忍時間,如果5s內無法讀寫,就即刻返回
tm := time.NewTimer(time.Second * 5)
// 使用select來獲取這兩個通道的值,然後輸出
select {
case data1 := <-c1: // 接收c1通道數據(消費數據)
fmt.Println(msg1)
case data2 := <-c2: // 接收c2通道數據(消費數據)
fmt.Println(msg2)
case <-tm.C:
fmt.Println("timeout!")
}
}
篇末提問
- 使用過協程嗎?知道協程與執行緒的區別嗎?
- 如果是單核CPU,開協程會有用嗎?
- 本文由於沒有幫助你提升code能力?
- 進程通訊方式有沒有一點點了解?
- 你會使用本文的協程案例提升運行速度嗎?