iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 28
0
自我挑戰組

Go to 放棄系列 第 28

go => goroutine + channel design single queue

建立兩個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

為正確的輸出結果
https://ithelp.ithome.com.tw/upload/images/20181112/20112477jrovS9DiSO.png


上一篇
go => use sync.Mutex to solve transaction issue
下一篇
go mutli queue
系列文
Go to 放棄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言