Go併發程式設計實踐

2021-07-28 10:48:32 字數 2553 閱讀 8743

併發程式設計一直是golang區別與其他語言的很大優勢,也是實際工作場景中經常遇到的。近日筆者在組內分享了我們常見的併發場景,及**示例,以期望大家能在遇到相同場景下,能快速的想到解決方案,或者是拿這些方案與自己實現的比較,取長補短。現整理出來與大家共享。

回到頂部

很多時候,我們只想併發的做一件事情,比如測試某個介面的是否支援併發。那麼我們就可以這麼做:

func

runscenario1

() (i)

}wg.wait()

}

使用goroutine來實現非同步,使用waitgroup來等待所有goroutine結束。這裡要注意的是要正確釋放waitgroup的counter(在goroutine裡呼叫done()方法)。

但此種方式有個弊端,就是當goroutine的量過多時,很容易消耗完客戶端的資源,導致程式表現不佳。

回到頂部

我們仍然以測試某個後端api介面為例,如果我們想知道這個介面在持續高併發情況下是否有控制代碼洩露,這種情況該如何測試呢?

這種時候,我們需要能控制時間的高併發模型:

func

runscenario2

() )

done := make(chan struct

{}) concurrentcount := make(chan struct

{}, n)

for i := 0; i < n; i++ {}

}go func

() {}

}waitforall

{}{}

}()go func

() {}

}()}

}()}

上面的**裡,我們通過乙個buffered channel來控制併發的數量(concurrentcount),然後另起乙個channel來週期性的發起新的任務,而控制的條件就是 time.now().before(timeout),這樣當超過規定的時間,waitforall 就會得到訊號,而使整個程式退出。

這是一種實現方式,那麼還有其他的方式沒?我們接著往下看。

回到頂部

前面說的基於時間的併發模型,那如果只知道資料量很大,但是具體結束時間不確定,該怎麼辦呢?

比如,客戶給了個幾tb的檔案列表,要求把這些檔案從儲存裡刪除。再比如,實現個爬蟲去爬某些**的所有內容。

而解決此類問題,最常見的就是使用工作池模式了(worker pool)。以刪檔案為例,我們可以簡單這樣來處理:

雖然這只是個簡單worker pool模型,但已經能滿足我們的需求:

func runscenario3() 

}for i := 0; i < numofconcurrency; i++

totaltasks := 100

// 本例就要從檔案列表裡讀取

wg.add(1)

gofunc()

close(results)

}()for i := 0; i < totaltasks; i++

close(jobs)

wg.wait()

}

在go裡,分發任務,收集結果,我們可以都交給channel來實現。從實現上更加的簡潔。

仔細看會發現,本模型也是適用於按時間來控制併發。只要把totaltask的遍歷換成時間控制就好了。

回到頂部

goroutine和channel的組合在實際程式設計時經常會用到,而加上select更是無往而不利。

func runscenario4() 

}()go

func()

}()select

}

在select的case情況,加上time.after()模型可以讓我們在一定時間範圍內等待非同步任務結果,防止程式卡死。

回到頂部

上面我們說到持續的壓測某後端api,但並未實時收集結果。而很多時候對於效能測試場景,實時的統計吞吐率,成功率是非常有必要的。

func

runscenario5()

}(i)

}t := time.newticker(time.second)

for } }

這種場景就需要使用到ticker,且上面的example模型還能控制併發數量,也是非常實用的方式。

回到頂部

上面我們共提到了五種併發模式:

歸納下來其核心就是使用了go的幾個知識點:goroutine, channel, select, time, timer/ticker, waitgroup. 若是對這些不清楚,可以自行google之。

另完整的example **可以參考這裡:

使用方式: go run main.go 《場景》

比如 :

Go併發程式設計實踐

併發程式設計一直是golang區別與其他語言的很大優勢,也是實際工作場景中經常遇到的。近日筆者在組內分享了我們常見的併發場景,及 示例,以期望大家能在遇到相同場景下,能快速的想到解決方案,或者是拿這些方案與自己實現的比較,取長補短。現整理出來與大家共享。很多時候,我們只想併發的做一件事情,比如測試某...

Go 併發程式設計

go語言宣揚用通訊的方式共享資料。go語言以獨特的併發程式設計模型傲視群雄,與併發程式設計關係最緊密的 包就是sync包,意思是同步。同步的用途有兩個,乙個是避免多個執行緒在同一時刻操作同乙個資料塊,另乙個是協調多個執行緒,以避免它們在同一時刻執行同一塊 由於這一的資料庫和 塊的背後都隱含著一種或多...

go併發程式設計

x ch 從ch中接收值並賦值給變數x ch 從ch中接收值,忽略結果關閉 我們通過呼叫內建的close函式來關閉通道。close ch 關於關閉通道需要注意的事情是,只有在通知接收方goroutine所有的資料都傳送完畢的時候才需要關閉通道。通道是可以被垃圾 機制 的,它和關閉檔案是不一樣的,在結...