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

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

如何跨 goroutines 共享地圖

如何跨 goroutines 共享地圖

Go
犯罪嫌疑人X 2023-04-04 14:40:40
我正在嘗試在 Go 中編寫一個通知結構,它將保存一系列鍵及其各自的值,并且如果值低于閾值將觸發通知。當第一個樣本低于閾值時,通知應該只觸發一次,并且低于該值的其他樣本不應再次觸發,直到值升至閾值以上。例如,假設我的閾值是 10,我發送了 15、14、11、10、... 9 的樣本。發送 9 后,應觸發通知。8、7、4 的進一步樣本不應造成任何影響。以下樣本如 5、6、7、9、10、11、14、30 不應執行任何操作。一旦樣本再次低于 10:30、20、15、10、7... 必須發送另一個通知。當多個 goroutines 操縱我的結構時,我遇到了問題。我嘗試使用 sync.Mutex 進行同步,還使用了 sync.Map,但沒有成功。我覺得某處有參考副本或緩存,但我對 Go 太陌生了,無法找到問題所在。為此,我創建了一個這樣的結構:type Notifier interface {    Send(message string)}type NotificationBoard struct {    mutex    sync.Mutex    Last     sync.Map    notifier Notifier}func (n *NotificationBoard) Init(notifier Notifier) {    n.notifier = notifier}// NotifyLess ...func (n *NotificationBoard) NotifyLess(key string, value, threshold float64) {    n.mutex.Lock()    defer n.mutex.Unlock()    if value >= threshold {        fmt.Printf("NotificationBoard.NotifyLess %v (value >= threshold): %v >= %v\n", key, value, threshold)        n.Last.Store(key, value)        return    }    // value < threshold    if last, found := n.Last.Load(key); found == true {        fmt.Printf("NotificationBoard.NotifyLess %v (value < threshold): %v < %v : found %v\n", key, value, threshold, last)        if last.(float64) >= threshold { // first trigger            n.notifier.Send(fmt.Sprintf("%s < %v (%v)", key, threshold, value))        }    } else {        fmt.Printf("NotificationBoard.NotifyLess %v (value < threshold): %v < %v : not found\n", key, value, threshold)        // not found, started board as less        n.notifier.Send(fmt.Sprintf("%s < %v (%v)", key, threshold, value))    }    n.Last.Store(key, value)    return}我知道使用 sync.Mutex 或 sync.Map 應該就足夠了,但上面的代碼兩者都有,因為它是我當前的(損壞的)版本。為了測試,我設置了以下代碼:type dummy struct{}func (d *dummy) Send(message string) {    fmt.Println("--------------> notifying", message)}func newBoard() *NotificationBoard {    notificationBoard := &NotificationBoard{}    notificationBoard.Init(&dummy{})    return notificationBoard}
查看完整描述

2 回答

?
嚕嚕噠

TA貢獻1784條經驗 獲得超7個贊

在這里簡化邏輯的一種方法可能是運行一個修改地圖的 goroutine。然后,它可以監聽通道上的新值(因為如果按順序處理值應該沒問題)。您需要小心知道您的 goroutine 何時返回以確保它不會泄漏。一般來說,你不應該在 goroutines 之間共享數據,你應該使用通道在 goroutines 之間進行通信。

這是一個示例,說明如何使用通道而不是共享內存(游樂場版本)來實現此類應用程序。

package main


import (

? ? "fmt"

? ? "sync"

)


type value struct {

? ? key? ? ? ?string

? ? value? ? ?float64

? ? threshold float64

}


func main() {

? ? b := board{

? ? ? ? last: map[string]float64{},

? ? }

? ? c := b.start()

? ? wg := sync.WaitGroup{}

? ? for i := 0; i < 30; i++ {

? ? ? ? wg.Add(1)

? ? ? ? go func(i int) {

? ? ? ? ? ? for j := 15.0; j > 5; j-- {

? ? ? ? ? ? ? ? c <- value{"k1", j + float64(i+1)/100, 10}

? ? ? ? ? ? }

? ? ? ? ? ? wg.Done()

? ? ? ? }(i)

? ? }

? ? wg.Wait()

? ? close(c)

}


type board struct {

? ? last map[string]float64

}


func (b *board) start() chan<- value {

? ? c := make(chan value)

? ? go func() {

? ? ? ? for v := range c {

? ? ? ? ? ? b.notify(v)

? ? ? ? }

? ? }()

? ? return c

}


func (b *board) notify(v value) {

? ? if l, ok := b.last[v.key]; !ok || l >= v.threshold {

? ? ? ? if v.value < v.threshold {

? ? ? ? ? ? fmt.Printf("%s < %v (%v)\n", v.key, v.threshold, v.value)

? ? ? ? }

? ? }

? ? b.last[v.key] = v.value

}


查看完整回答
反對 回復 2023-04-04
?
當年話下

TA貢獻1890條經驗 獲得超9個贊

我認為您在設置此類跟蹤器時需要設置標志,一個用于價值上升,另一個用于價值下降。我實施了一個


package main


import (

    "fmt"

    "sync"

)


const (

    threshold      int = 10

    upperThreshold int = 20

)


var mu sync.Mutex

var downwatch bool

var upwatch bool


func main() {

    var tracker int = 10

    var temp int = 1

    var sign int = 1

    for i := 1; i < 20; i++ {

        sign = sign * -1

        temp = temp + i

        go UpdateTracker(&tracker, temp*sign)

    }


    for {

    }

    return

}

func SetDownWatch() {

    downwatch = true

}

func SetUpWatch() {

    upwatch = true

}

func UnSetDownWatch() {

    downwatch = false

}

func UnSetUpWatch() {

    upwatch = false

}


func UpdateTracker(tracker *int, val int) {

    mu.Lock()

    defer mu.Unlock()

    if !(upwatch || downwatch) {

        if (*tracker)+val < threshold {

            NotifyOnDrop()

            SetDownWatch()

        }

        if (*tracker + val) > upperThreshold {

            NotifyOnRise()

            SetUpWatch()

        }


    }

    if (*tracker)+val < threshold && upwatch {

        NotifyOnDrop()

        SetDownWatch()

        UnSetUpWatch()

    }


    if (*tracker+val) > upperThreshold && downwatch {

        NotifyOnRise()

        SetUpWatch()

        UnSetDownWatch()

    }


    *tracker = (*tracker) + val

    fmt.Println((*tracker))

    return

}


func NotifyOnDrop() {

    fmt.Println("dropped")

    return

}


func NotifyOnRise() {

    fmt.Println("rose")

    return

}

updateTracker當值超過設置的閾值時,作為 go 例程運行并打印到控制臺。我認為這就是您正在尋找的功能,這里缺少的是Last.Store我認為是您的代碼自定義的功能。我相信還有其他方法可以處理這個問題。這對我來說似乎很簡單。


查看完整回答
反對 回復 2023-04-04
  • 2 回答
  • 0 關注
  • 181 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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