亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何同步常量寫入和周期性讀取和更新

如何同步常量寫入和周期性讀取和更新

Go
蝴蝶不菲 2022-05-18 10:13:38
定義問題:我們有這個物聯網設備,每個設備都會向我們發送有關汽車位置的日志。我們要計算汽車在線行駛的距離!因此,當日志出現時(將其放入隊列等之后),我們會這樣做:type Delta struct {    DeviceId string    time     int64    Distance float64}var LastLogs = make(map[string]FullLog)var Distances = make(map[string]Delta)func addLastLog(l FullLog) {    LastLogs[l.DeviceID] = l}func AddToLogPerDay(l FullLog) {    //mutex.Lock()    if val, ok := LastLogs[l.DeviceID]; ok {        if distance, exist := Distances[l.DeviceID]; exist {            x := computingDistance(val, l)            Distances[l.DeviceID] = Delta{                DeviceId: l.DeviceID,                time:     distance.time + 1,                Distance: distance.Distance + x,            }        } else {            Distances[l.DeviceID] = Delta{                DeviceId: l.DeviceID,                time:     1,                Distance: 0,            }        }    }    addLastLog(l)}它基本上使用效用函數計算距離!因此,在Distances每個設備中,ID 都映射到了一定距離!現在是問題開始的地方:雖然這個距離被添加到Distances map,我想要一個 go 例程來把這個數據放在數據庫中,但是因為有很多設備和很多日志等等,對每個日志進行這個查詢并不是一個好主意. 所以我需要每 5 秒執行一次,這意味著每 5 秒嘗試清空添加到地圖的所有最后距離的列表。我寫了這個函數:func UpdateLogPerDayTable() {    for {        for _, distance := range Distances {            logs := model.HourPerDay{}            result := services.CarDBProvider.DB.Table(model.HourPerDay{}.TableName()).    }}它go utlis.UpdateLogPerDayTable()在另一個 goroutine 上被調用。但是這里有很多問題:我不知道如何保護Distances,所以當我將它添加到另一個例程中時,我在其他地方閱讀它,一切都很好!(問題是我想使用 go 頻道并且不知道該怎么做)對于這個問題,我如何安排任務?可能我會添加一個 redis 來存儲所有在線設備,這樣我就可以更快地進行選擇查詢并更新實際的數據庫。還為 redis 添加過期時間,因此如果設備在一段時間內沒有發送和數據,它就會消失!我應該把這段代碼放在哪里?對不起,如果我的解釋還不夠,但我真的需要一些幫助。專門用于代碼實現
查看完整描述

1 回答

?
慕容3067478

TA貢獻1773條經驗 獲得超3個贊

Go 有一個非常酷的模式,在多個通道上使用for / select 。這允許您使用超時和最大記錄大小來批量寫入距離。使用這種模式需要使用通道。


首先是將您的距離建模為通道:


distances := make(chan Delta)

然后你跟蹤當前批次


var deltas []Delta

然后


ticker := time.NewTicker(time.Second * 5)


var deltas []Delta


for {

  select {

     case <-ticker.C:

        // 5 seconds up flush to db

        // reset deltas

     case d := <-distances:

        deltas = append(deltas, d)

        if len(deltas) >= maxDeltasPerFlush {

           // flush

           // reset deltas

        }

  }

}

我不知道如何確保距離,所以當我在另一個例程中添加它時,我在其他地方閱讀它,一切都很好?。▎栴}是我想使用 go 頻道并且不知道該怎么做)


如果您打算保留地圖并共享內存,則需要使用互斥(互斥)來保護它,以同步 go 例程之間的訪問。使用通道允許您將副本發送到通道,從而無需跨 Delta 對象進行同步。根據您的架構,您還可以創建由通道連接的 go 例程管道,這可以使其只有一個 go 例程(monitor goroutine)正在訪問Delta,也無需同步。


對于這個問題,我如何安排任務?


使用通道作為傳遞Deltas給不同 go 例程的原語 :)


可能我會添加一個 redis 來存儲所有在線設備,這樣我就可以更快地進行選擇查詢并更新實際的數據庫。還為 redis 添加過期時間,因此如果設備在一段時間內沒有發送和數據,它就會消失!我應該把這段代碼放在哪里?


這取決于您完成的架構。您可以為 select 操作編寫一個裝飾器,它會先檢查 redis,然后再訪問數據庫。此功能的客戶端不必知道這一點。寫操作可以以相同的方式完成:寫入持久存儲,然后使用緩存值和過期時間寫回 redis。使用裝飾器,客戶端不需要知道這一點,他們只需執行讀取和寫入,緩存邏輯將在裝飾器內部實現。有很多方法可以做到這一點,這在很大程度上取決于您的實現在哪里解決。


查看完整回答
反對 回復 2022-05-18
  • 1 回答
  • 0 關注
  • 176 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號