Offensichtlich habe ich eine Race Condition in meinem Go-Code. Aber ich kann es nicht finden, da ich ziemlich sicher bin, dass ich richtig synchronisiere. Nach stundenlangem Debuggen können Sie mir wahrscheinlich helfen, es zu finden.Golang: Seltsames Verhalten mit Funktionstyp
Zunächst einmal ist hier meine (sehr vereinfacht) Code:
package main
import (
"log"
"time"
)
type Parser struct {
callback Callback
callbackSet chan bool
test int
}
func NewParser() Parser {
p := Parser{}
p.test = 100
p.callbackSet = make(chan bool)
return p
}
func (p *Parser) SetCallback(newCallback Callback) {
log.Println("=> SET CALLBACK: ", newCallback)
p.test = 100
p.callback = newCallback
log.Println("=> SETTING CALLBACK DONE")
p.callbackSet <- true
}
func (p *Parser) StartParsing() {
go p.parse()
}
func (p *Parser) parse() {
cb := <-p.callbackSet
_ = cb
log.Println("Verify Callback: ", p.callback)
log.Println("Verify Test Variable: ", p.test)
funcDone := make(chan bool)
go func() {
time.Sleep(3 * time.Second) // Some io-Operation here
funcDone <- true
}()
_ = <-funcDone
}
type Callback func(Message)
type Message int
type Dialog struct {
Parser Parser
}
func CreateDialog() (Dialog, error) {
d := Dialog{}
d.Parser = NewParser()
d.Parser.StartParsing()
return d, nil
}
func (d *Dialog) OnMessage(callback Callback) {
log.Println("dialog.OnMessage: ", callback)
time.Sleep(3 * time.Second) // This sleep is just to prove the synchronization. It could be removed.
d.Parser.SetCallback(callback)
}
func main() {
dialog, _ := CreateDialog()
dialog.OnMessage(func(m Message){
log.Println("Message: ", m)
})
time.Sleep(5 * time.Second) // Not clean but just to await all of the output
}
Die große Frage ist nun: Warum ist p.callback
<nil>
in p.parse
während p.test
ist nicht, obwohl diese beiden an der gleichen gesetzt Zeit?
Und das Zeug sollte mit dem Kanal p.callbackSet
synchronisiert werden?!
Fully runnable Beispiel bei https://play.golang.org/p/14vn5Tie5Y
Ich habe versucht, durch einen einfacheren die Hauptfunktion zu ersetzen. Ich vermute, dass der Fehler irgendwo in der Dialog
Struktur liegt. Wenn ich die Verwendung umgehe, kann ich das Problem nicht reproduzieren:
func main() {
p := NewParser()
p.StartParsing()
p.SetCallback(func (m Message) {
log.Println("Message: ", m)
})
time.Sleep(5 * time.Second) // Not clean but just to await all of the output
}
Der Rest des Codes bleibt gleich. Ein weiteres spielbares Beispiel der modifizierten (Arbeits-) Version hier: https://play.golang.org/p/0Y0nKbfcrv
Meine Antwort ist (zur Zeit) falsch, aber ich habe durch den Spielplatz geschaut: das Problem ist nicht exklusiv für 'p.callback', als ob man versucht,' p.test' in 'SetCallback()' zu ändern der Standardwert später. –