golang乙個例子引出的幾個問題

2021-09-22 14:16:48 字數 2237 閱讀 9772

這個例子是從go原始碼src/pkg/net/rpc/server_test.go擷取出來的

func benchmarkendtoendasync(dial func() (*client, error), b *testing.b) 

// asynchronous calls

args := &args

procs := 4 * runtime.gomaxprocs(-1)

send := int32(b.n)

recv := int32(b.n)

var wg sync.waitgroup

wg.add(procs)

gate := make(chan bool, maxconcurrentcalls)

res := make(chan *call, maxconcurrentcalls)

b.starttimer()

for p := 0; p < procs; p++

}()go func()

if atomic.addint32(&recv, -1) == 0

}wg.done()

}()}

wg.wait()

}

這個**用來對rpc的客戶端go函式進行壓力測試。

這裡有幾個地方值得揣摩下:

先使用startserver(這個函式裡面具體是開啟了乙個routine)進行伺服器服務。然後在每個測試用例中啟動server,如果是benchtest的話記得這裡的timer要在啟動伺服器行為之後再開啟。

wg變數是sync.waitgroup型別,add增加計數,done減少計數,wait進行阻塞等待,等計數減為0的時候再停止阻塞。

這裡如果不使用waitgroup進行wait阻塞的話,主routine會先於次routine先結束。會導致程式提早退出。

因此這裡也給出了乙個測試用例中測試非同步函式的方法。就是使用waitgroup

看起來gate好像是沒什麼用啊,如果去掉gate呢?有可能會出現「rpc: discarding call reply due to insufficient done chan capacity」

這個gate完全是因為client.go這個函式,rpc包的client.go是非同步的呼叫,雖然是非同步呼叫,這個非同步呼叫的最後乙個done引數是乙個channel buffer。

當client.go進行完rpc呼叫後,將訊號傳入這個channel buffer。但是這個channel buffer卻是不會阻塞的。

具體看原始碼:

這裡select加了個default分支,說明了done是非阻塞的。看注釋,作者認為這個buffer的大小容量應該由呼叫者來保證。rpc包並不保證容量大小。

方法有個兩個:

這個方法就是gate的使用原因了。只有gate容量有剩餘的時候才會容許呼叫client.go

在這個例子中,bench的channel最大只會是b.n,所以,如果我們分配的res的channel buffer大小為b.n也能解決這個問題。

這個方法導致的效果就是bench的時間變快了,但是mem分配增加了。

因為這裡會有多個routine會對send和recive進行操作,這裡就需要保證原子性。

多個併發routine對乙個共享變數進行操作有兩種方法,channel和鎖。

這裡當然使用channel也能起到原子操作的效果。sync包的atomic和sync的mutex都是鎖的方式。

所以說這裡其實可以使用channel,mutex,atomic三種方法。

bench test在執行前自身會呼叫runtime.gomaxprocs進行多核的設定,然後再每個處理器中並行執行測試。

這裡的runtime.gomaxprocs(-1)是獲取你要跑的cpu核數,這個核數是根據bench test的 -test.cpu設定的。具體可以看下src/testing/testing.go parsecpulist。在沒有設定過gomaxprocs和test.cpu的情況下,這裡的runtime.gomaxprocs就預設是1。

你可以使用-test.cpu 1,2,4來設定你的壓力測試用例是有幾個cpu,每個cpu是幾核的。

這裡的procs設定為處理器核數的4倍就是為了測試routine能分配遠大於核數的個數,這樣每個核承擔的goroutine能大於1。

上面的for迴圈就是保證起的routine數是足夠的。

golang,使用型別斷言的乙個例子

type spotprice struct var pricei inte ce var err error pricei,err db.getspotprice realprice.productid,1,1 if err nil value pricei.price.spotprice real...

LineDDA的乙個例子

unit unit1 inte ce uses windows,messages,sysutils,variants,classes,graphics,controls,forms,dialogs,extctrls,stdctrls,buttons type tfmmain class tform ...

SQL GROUP CONCAT的乙個例子

我有乙個這樣的資料庫 user info 現在有乙個需求是把這樣 9 條記錄按照 username 來 group 成3條記錄 目標 shu female 201 lee male 202 yuki female 181 如果用select from user info group by usern...