併發程式設計一直是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所有的資料都傳送完畢的時候才需要關閉通道。通道是可以被垃圾 機制 的,它和關閉檔案是不一樣的,在結...