建立兩個channel (in out)
var in chan string
var out chan result
type result struct {
Account string // 使用者帳號
Result float64 // 輸出結果
}
在main function建立goroutine
go func(in *chan string) {
for {
select {
case account := <-*in:
entry := currency{}
// step 1: get current amount
err := globalDB.C("test").Find(bson.M{"account": account}).One(&entry)
if err != nil {
panic(err)
}
//step 3: subtract current balance and update back to database
entry.Amount = entry.Amount + 50.000
err = globalDB.C("test").UpdateId(entry.ID, &entry)
if err != nil {
panic("update error")
}
out <- result{
Account: account,
Result: entry.Amount,
}
}
}
}(&in)
select來接受input channel,利用for loop在背景執行
因為queue特性,排隊依序處理
所以在每個交易時,將帳號丟到 in channel 內,就可以開始進行交易,同時間並不會有其他交易
在pay handler裡,也是透過queue來印出當前的餘額
func pay(w http.ResponseWriter, r *http.Request) {
wg := sync.WaitGroup{}
wg.Add(1)
go func(wg *sync.WaitGroup) {
in <- account
for {
select {
case data := <-out:
fmt.Printf("%+v\n", data)
wg.Done() // -1的意思
return
}
}
}(&wg)
wg.Wait()
io.WriteString(w, "ok")
}
再利用vegeta製造100個request打在3001port上
echo "GET http://localhost:3001" | vegeta attack -rate=100 -connections=1 -duration=1s | tee results.bin | vegeta report
為正確的輸出結果