Bugfix/improvement: Orderbook/ticker update processing (#364)

* Greatly increases efficiency of web socket orderbook processing by minimising multiple map lookups. Changes buffer to use pointers. Ensures orderbook benchmarks are on equal footing and set correctly. Removes data race by not setting waitgroup adds inside go routine causing wait and add to happen simultaneously. Updates ticker and orderbook service to use a pointer var instead of map lookups when setting data.

* Removes misguided comment

* Removes waitgroups and goroutines for updating bids and asks for non-id orderbook updates via websocket. Updates benchmarks to be consistent
This commit is contained in:
Scott
2019-10-04 16:24:29 +10:00
committed by Adrian Gallagher
parent 8ca1e5c36f
commit 62a528a064
7 changed files with 197 additions and 92 deletions

View File

@@ -95,11 +95,12 @@ func (s *Service) Update(b *Base) error {
}
default:
s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].b.Bids = b.Bids
s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].b.Asks = b.Asks
s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].b.LastUpdated = b.LastUpdated
ids = s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].Assoc
ids = append(ids, s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType].Main)
book := s.Books[b.ExchangeName][b.Pair.Base.Item][b.Pair.Quote.Item][b.AssetType]
book.b.Bids = b.Bids
book.b.Asks = b.Asks
book.b.LastUpdated = b.LastUpdated
ids = book.Assoc
ids = append(ids, book.Main)
}
s.Unlock()
return s.mux.Publish(ids, b)

View File

@@ -147,19 +147,20 @@ func (s *Service) Update(p *Price) error {
}
default:
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Last = p.Last
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].High = p.High
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Low = p.Low
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Bid = p.Bid
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Ask = p.Ask
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Volume = p.Volume
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].QuoteVolume = p.QuoteVolume
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].PriceATH = p.PriceATH
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Open = p.Open
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Close = p.Close
s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].LastUpdated = p.LastUpdated
ids = s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Assoc
ids = append(ids, s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType].Main)
ticker := s.Tickers[p.ExchangeName][p.Pair.Base.Item][p.Pair.Quote.Item][p.AssetType]
ticker.Last = p.Last
ticker.High = p.High
ticker.Low = p.Low
ticker.Bid = p.Bid
ticker.Ask = p.Ask
ticker.Volume = p.Volume
ticker.QuoteVolume = p.QuoteVolume
ticker.PriceATH = p.PriceATH
ticker.Open = p.Open
ticker.Close = p.Close
ticker.LastUpdated = p.LastUpdated
ids = ticker.Assoc
ids = append(ids, ticker.Main)
}
s.Unlock()
return s.mux.Publish(ids, p)

View File

@@ -92,6 +92,7 @@ func (w *Websocket) Connect() error {
go w.connectionMonitor()
}
if w.SupportsFunctionality(WebsocketSubscribeSupported) || w.SupportsFunctionality(WebsocketUnsubscribeSupported) {
w.Wg.Add(1)
go w.manageSubscriptions()
}
@@ -498,7 +499,6 @@ func (w *Websocket) manageSubscriptions() {
w.DataHandler <- fmt.Errorf("%v does not support channel subscriptions, exiting ManageSubscriptions()", w.exchangeName)
return
}
w.Wg.Add(1)
defer func() {
if w.verbose {
log.Debugf(log.WebsocketMgr, "%v ManageSubscriptions exiting", w.exchangeName)

View File

@@ -352,12 +352,13 @@ func TestManageSubscriptionsStartStop(t *testing.T) {
ShutdownC: make(chan struct{}),
Functionality: WebsocketSubscribeSupported | WebsocketUnsubscribeSupported,
}
w.Wg.Add(1)
go w.manageSubscriptions()
close(w.ShutdownC)
w.Wg.Wait()
}
// TestManageSubscriptionsStartStop logic test
// TestManageSubscriptions logic test
func TestManageSubscriptions(t *testing.T) {
w := Websocket{
ShutdownC: make(chan struct{}),

View File

@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"sort"
"sync"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
@@ -33,21 +32,22 @@ func (w *WebsocketOrderbookLocal) Update(orderbookUpdate *WebsocketOrderbookUpda
}
w.m.Lock()
defer w.m.Unlock()
if _, ok := w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]; !ok {
obLookup, ok := w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]
if !ok {
return fmt.Errorf("ob.Base could not be found for Exchange %s CurrencyPair: %s AssetType: %s",
w.exchangeName,
orderbookUpdate.CurrencyPair.String(),
orderbookUpdate.AssetType)
}
if w.bufferEnabled {
overBufferLimit := w.processBufferUpdate(orderbookUpdate)
overBufferLimit := w.processBufferUpdate(obLookup, orderbookUpdate)
if !overBufferLimit {
return nil
}
} else {
w.processObUpdate(orderbookUpdate)
w.processObUpdate(obLookup, orderbookUpdate)
}
err := w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Process()
err := obLookup.Process()
if err != nil {
return err
}
@@ -58,144 +58,142 @@ func (w *WebsocketOrderbookLocal) Update(orderbookUpdate *WebsocketOrderbookUpda
return nil
}
func (w *WebsocketOrderbookLocal) processBufferUpdate(orderbookUpdate *WebsocketOrderbookUpdate) bool {
func (w *WebsocketOrderbookLocal) processBufferUpdate(o *orderbook.Base, orderbookUpdate *WebsocketOrderbookUpdate) bool {
if w.buffer == nil {
w.buffer = make(map[currency.Pair]map[asset.Item][]WebsocketOrderbookUpdate)
w.buffer = make(map[currency.Pair]map[asset.Item][]*WebsocketOrderbookUpdate)
}
if w.buffer[orderbookUpdate.CurrencyPair] == nil {
w.buffer[orderbookUpdate.CurrencyPair] = make(map[asset.Item][]WebsocketOrderbookUpdate)
w.buffer[orderbookUpdate.CurrencyPair] = make(map[asset.Item][]*WebsocketOrderbookUpdate)
}
if len(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]) <= w.obBufferLimit {
w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType] = append(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType], *orderbookUpdate)
if len(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]) < w.obBufferLimit {
bufferLookup := w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]
if len(bufferLookup) <= w.obBufferLimit {
bufferLookup = append(bufferLookup, orderbookUpdate)
if len(bufferLookup) < w.obBufferLimit {
w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType] = bufferLookup
return false
}
}
if w.sortBuffer {
// sort by last updated to ensure each update is in order
if w.sortBufferByUpdateIDs {
sort.Slice(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType], func(i, j int) bool {
return w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][i].UpdateID < w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][j].UpdateID
sort.Slice(bufferLookup, func(i, j int) bool {
return bufferLookup[i].UpdateID < bufferLookup[j].UpdateID
})
} else {
sort.Slice(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType], func(i, j int) bool {
return w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][i].UpdateTime.Before(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][j].UpdateTime)
sort.Slice(bufferLookup, func(i, j int) bool {
return bufferLookup[i].UpdateTime.Before(bufferLookup[j].UpdateTime)
})
}
}
for i := 0; i < len(w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType]); i++ {
w.processObUpdate(&w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType][i])
for i := 0; i < len(bufferLookup); i++ {
w.processObUpdate(o, bufferLookup[i])
}
w.buffer[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType] = bufferLookup
return true
}
func (w *WebsocketOrderbookLocal) processObUpdate(orderbookUpdate *WebsocketOrderbookUpdate) {
func (w *WebsocketOrderbookLocal) processObUpdate(o *orderbook.Base, orderbookUpdate *WebsocketOrderbookUpdate) {
if w.updateEntriesByID {
w.updateByIDAndAction(orderbookUpdate)
w.updateByIDAndAction(o, orderbookUpdate)
} else {
var wg sync.WaitGroup
wg.Add(2)
go w.updateAsksByPrice(orderbookUpdate, &wg)
go w.updateBidsByPrice(orderbookUpdate, &wg)
wg.Wait()
w.updateAsksByPrice(o, orderbookUpdate)
w.updateBidsByPrice(o, orderbookUpdate)
}
}
func (w *WebsocketOrderbookLocal) updateAsksByPrice(base *WebsocketOrderbookUpdate, wg *sync.WaitGroup) {
func (w *WebsocketOrderbookLocal) updateAsksByPrice(o *orderbook.Base, base *WebsocketOrderbookUpdate) {
for j := 0; j < len(base.Asks); j++ {
found := false
for k := 0; k < len(w.ob[base.CurrencyPair][base.AssetType].Asks); k++ {
if w.ob[base.CurrencyPair][base.AssetType].Asks[k].Price == base.Asks[j].Price {
for k := 0; k < len(o.Asks); k++ {
if o.Asks[k].Price == base.Asks[j].Price {
found = true
if base.Asks[j].Amount == 0 {
w.ob[base.CurrencyPair][base.AssetType].Asks = append(w.ob[base.CurrencyPair][base.AssetType].Asks[:k],
w.ob[base.CurrencyPair][base.AssetType].Asks[k+1:]...)
o.Asks = append(o.Asks[:k],
o.Asks[k+1:]...)
break
}
w.ob[base.CurrencyPair][base.AssetType].Asks[k].Amount = base.Asks[j].Amount
o.Asks[k].Amount = base.Asks[j].Amount
break
}
}
if !found {
w.ob[base.CurrencyPair][base.AssetType].Asks = append(w.ob[base.CurrencyPair][base.AssetType].Asks, base.Asks[j])
o.Asks = append(o.Asks, base.Asks[j])
}
}
sort.Slice(w.ob[base.CurrencyPair][base.AssetType].Asks, func(i, j int) bool {
return w.ob[base.CurrencyPair][base.AssetType].Asks[i].Price < w.ob[base.CurrencyPair][base.AssetType].Asks[j].Price
sort.Slice(o.Asks, func(i, j int) bool {
return o.Asks[i].Price < o.Asks[j].Price
})
wg.Done()
}
func (w *WebsocketOrderbookLocal) updateBidsByPrice(base *WebsocketOrderbookUpdate, wg *sync.WaitGroup) {
func (w *WebsocketOrderbookLocal) updateBidsByPrice(o *orderbook.Base, base *WebsocketOrderbookUpdate) {
for j := 0; j < len(base.Bids); j++ {
found := false
for k := 0; k < len(w.ob[base.CurrencyPair][base.AssetType].Bids); k++ {
if w.ob[base.CurrencyPair][base.AssetType].Bids[k].Price == base.Bids[j].Price {
for k := 0; k < len(o.Bids); k++ {
if o.Bids[k].Price == base.Bids[j].Price {
found = true
if base.Bids[j].Amount == 0 {
w.ob[base.CurrencyPair][base.AssetType].Bids = append(w.ob[base.CurrencyPair][base.AssetType].Bids[:k],
w.ob[base.CurrencyPair][base.AssetType].Bids[k+1:]...)
o.Bids = append(o.Bids[:k],
o.Bids[k+1:]...)
break
}
w.ob[base.CurrencyPair][base.AssetType].Bids[k].Amount = base.Bids[j].Amount
o.Bids[k].Amount = base.Bids[j].Amount
break
}
}
if !found {
w.ob[base.CurrencyPair][base.AssetType].Bids = append(w.ob[base.CurrencyPair][base.AssetType].Bids, base.Bids[j])
o.Bids = append(o.Bids, base.Bids[j])
}
}
sort.Slice(w.ob[base.CurrencyPair][base.AssetType].Bids, func(i, j int) bool {
return w.ob[base.CurrencyPair][base.AssetType].Bids[i].Price > w.ob[base.CurrencyPair][base.AssetType].Bids[j].Price
sort.Slice(o.Bids, func(i, j int) bool {
return o.Bids[i].Price > o.Bids[j].Price
})
wg.Done()
}
// updateByIDAndAction will receive an action to execute against the orderbook
// it will then match by IDs instead of price to perform the action
func (w *WebsocketOrderbookLocal) updateByIDAndAction(orderbookUpdate *WebsocketOrderbookUpdate) {
func (w *WebsocketOrderbookLocal) updateByIDAndAction(o *orderbook.Base, orderbookUpdate *WebsocketOrderbookUpdate) {
switch orderbookUpdate.Action {
case "update":
for _, target := range orderbookUpdate.Bids {
for i := range w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids {
if w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[i].ID == target.ID {
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[i].Amount = target.Amount
for i := range o.Bids {
if o.Bids[i].ID == target.ID {
o.Bids[i].Amount = target.Amount
break
}
}
}
for _, target := range orderbookUpdate.Asks {
for i := range w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks {
if w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[i].ID == target.ID {
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[i].Amount = target.Amount
for i := range o.Asks {
if o.Asks[i].ID == target.ID {
o.Asks[i].Amount = target.Amount
break
}
}
}
case "delete":
for _, target := range orderbookUpdate.Bids {
for i := 0; i < len(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids); i++ {
if w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[i].ID == target.ID {
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids = append(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[:i],
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids[i+1:]...)
for i := 0; i < len(o.Bids); i++ {
if o.Bids[i].ID == target.ID {
o.Bids = append(o.Bids[:i],
o.Bids[i+1:]...)
i--
break
}
}
}
for _, target := range orderbookUpdate.Asks {
for i := 0; i < len(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks); i++ {
if w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[i].ID == target.ID {
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks = append(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[:i],
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks[i+1:]...)
for i := 0; i < len(o.Asks); i++ {
if o.Asks[i].ID == target.ID {
o.Asks = append(o.Asks[:i],
o.Asks[i+1:]...)
i--
break
}
}
}
case "insert":
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids = append(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Bids, orderbookUpdate.Bids...)
w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks = append(w.ob[orderbookUpdate.CurrencyPair][orderbookUpdate.AssetType].Asks, orderbookUpdate.Asks...)
o.Bids = append(o.Bids, orderbookUpdate.Bids...)
o.Asks = append(o.Asks, orderbookUpdate.Asks...)
}
}
@@ -227,10 +225,11 @@ func (w *WebsocketOrderbookLocal) LoadSnapshot(newOrderbook *orderbook.Base) err
if w.ob[newOrderbook.Pair] == nil {
w.ob[newOrderbook.Pair] = make(map[asset.Item]*orderbook.Base)
}
if w.ob[newOrderbook.Pair][newOrderbook.AssetType] != nil &&
(len(w.ob[newOrderbook.Pair][newOrderbook.AssetType].Asks) > 0 ||
len(w.ob[newOrderbook.Pair][newOrderbook.AssetType].Bids) > 0) {
w.ob[newOrderbook.Pair][newOrderbook.AssetType] = newOrderbook
fullObLookup := w.ob[newOrderbook.Pair][newOrderbook.AssetType]
if fullObLookup != nil &&
(len(fullObLookup.Asks) > 0 ||
len(fullObLookup.Bids) > 0) {
fullObLookup = newOrderbook
return newOrderbook.Process()
}
w.ob[newOrderbook.Pair][newOrderbook.AssetType] = newOrderbook

View File

@@ -43,6 +43,61 @@ func createSnapshot() (obl *WebsocketOrderbookLocal, curr currency.Pair, asks, b
return
}
func bidAskGenerator() []orderbook.Item {
var response []orderbook.Item
randIterator := 100
for i := 0; i < randIterator; i++ {
price := float64(rand.Intn(1000))
if price == 0 {
price = 1
}
response = append(response, orderbook.Item{
Amount: float64(rand.Intn(1)),
Price: price,
ID: int64(i),
})
}
return response
}
func BenchmarkUpdateBidsByPrice(b *testing.B) {
ob, curr, _, _, err := createSnapshot()
if err != nil {
b.Error(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
bidAsks := bidAskGenerator()
update := &WebsocketOrderbookUpdate{
Bids: bidAsks,
Asks: bidAsks,
CurrencyPair: curr,
UpdateTime: time.Now(),
AssetType: asset.Spot,
}
ob.updateBidsByPrice(ob.ob[curr][asset.Spot], update)
}
}
func BenchmarkUpdateAsksByPrice(b *testing.B) {
ob, curr, _, _, err := createSnapshot()
if err != nil {
b.Error(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
bidAsks := bidAskGenerator()
update := &WebsocketOrderbookUpdate{
Bids: bidAsks,
Asks: bidAsks,
CurrencyPair: curr,
UpdateTime: time.Now(),
AssetType: asset.Spot,
}
ob.updateAsksByPrice(ob.ob[curr][asset.Spot], update)
}
}
// BenchmarkBufferPerformance demonstrates buffer more performant than multi
// process calls
func BenchmarkBufferPerformance(b *testing.B) {
@@ -50,6 +105,42 @@ func BenchmarkBufferPerformance(b *testing.B) {
if err != nil {
b.Fatal(err)
}
obl.bufferEnabled = true
cp := currency.NewPairFromString("BTCUSD")
// This is to ensure we do not send in zero orderbook info to our main book
// in orderbook.go, orderbooks should not be zero even after an update.
dummyItem := orderbook.Item{
Amount: 1333337,
Price: 1337.1337,
ID: 1337,
}
obl.ob[cp][asset.Spot].Bids = append(obl.ob[cp][asset.Spot].Bids, dummyItem)
update := &WebsocketOrderbookUpdate{
Bids: bids,
Asks: asks,
CurrencyPair: curr,
UpdateTime: time.Now(),
AssetType: asset.Spot,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
randomIndex := rand.Intn(4)
update.Asks = itemArray[randomIndex]
update.Bids = itemArray[randomIndex]
err = obl.Update(update)
if err != nil {
b.Fatal(err)
}
}
}
// BenchmarkBufferSortingPerformance benchmark
func BenchmarkBufferSortingPerformance(b *testing.B) {
obl, curr, asks, bids, err := createSnapshot()
if err != nil {
b.Fatal(err)
}
obl.bufferEnabled = true
obl.sortBuffer = true
cp := currency.NewPairFromString("BTCUSD")
// This is to ensure we do not send in zero orderbook info to our main book
@@ -67,8 +158,9 @@ func BenchmarkBufferPerformance(b *testing.B) {
UpdateTime: time.Now(),
AssetType: asset.Spot,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
randomIndex := rand.Intn(5)
randomIndex := rand.Intn(4)
update.Asks = itemArray[randomIndex]
update.Bids = itemArray[randomIndex]
err = obl.Update(update)
@@ -79,14 +171,23 @@ func BenchmarkBufferPerformance(b *testing.B) {
}
// BenchmarkBufferSortingPerformance benchmark
func BenchmarkBufferSortingPerformance(b *testing.B) {
func BenchmarkBufferSortingByIDPerformance(b *testing.B) {
obl, curr, asks, bids, err := createSnapshot()
if err != nil {
b.Fatal(err)
}
obl.sortBuffer = true
obl.bufferEnabled = true
obl.obBufferLimit = 5
obl.sortBuffer = true
obl.sortBufferByUpdateIDs = true
cp := currency.NewPairFromString("BTCUSD")
// This is to ensure we do not send in zero orderbook info to our main book
// in orderbook.go, orderbooks should not be zero even after an update.
dummyItem := orderbook.Item{
Amount: 1333337,
Price: 1337.1337,
ID: 1337,
}
obl.ob[cp][asset.Spot].Bids = append(obl.ob[cp][asset.Spot].Bids, dummyItem)
update := &WebsocketOrderbookUpdate{
Bids: bids,
Asks: asks,
@@ -94,8 +195,9 @@ func BenchmarkBufferSortingPerformance(b *testing.B) {
UpdateTime: time.Now(),
AssetType: asset.Spot,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
randomIndex := rand.Intn(5)
randomIndex := rand.Intn(4)
update.Asks = itemArray[randomIndex]
update.Bids = itemArray[randomIndex]
err = obl.Update(update)
@@ -128,8 +230,9 @@ func BenchmarkNoBufferPerformance(b *testing.B) {
UpdateTime: time.Now(),
AssetType: asset.Spot,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
randomIndex := rand.Intn(5)
randomIndex := rand.Intn(4)
update.Asks = itemArray[randomIndex]
update.Bids = itemArray[randomIndex]
err = obl.Update(update)

View File

@@ -13,7 +13,7 @@ import (
// appending and deleting changes and updates the main store in wsorderbook.go
type WebsocketOrderbookLocal struct {
ob map[currency.Pair]map[asset.Item]*orderbook.Base
buffer map[currency.Pair]map[asset.Item][]WebsocketOrderbookUpdate
buffer map[currency.Pair]map[asset.Item][]*WebsocketOrderbookUpdate
obBufferLimit int
bufferEnabled bool
sortBuffer bool