L'éditeur PHP Apple vous donnera la réponse : Dans le langage Go, lorsqu'une erreur survient dans une goroutine, elle ne sera pas automatiquement propagée à la coroutine principale. Au lieu de cela, il est ignoré en silence, ce qui peut entraîner la réception d'erreurs partielles plutôt que d'erreurs dans toutes les goroutines lancées. En effet, l'intention initiale de la conception du langage Go est de maintenir le programme stable et efficace, et l'ensemble du programme ne sera pas arrêté immédiatement, même en cas d'erreur. Si vous souhaitez détecter toutes les erreurs, vous pouvez utiliser un canal ou un autre mécanisme pour transmettre explicitement les informations sur les erreurs. De cette façon, vous pouvez vous assurer que toutes les erreurs sont traitées correctement.
J'ai défini une classe de cycle pour gérer les tâches simultanées. Ce que je veux, c'est exécuter deux fonctions, chacune dans une goroutine, attendre qu'elles se terminent et fusionner leurs erreurs de sortie. Mais je n'obtiens qu'une erreur. Les responsabilités de chaque méthode sont les suivantes :
run
- Exécuter une fonction dans une goroutine et collecter ses erreurs
waitalldone
- Fusionnez toutes les erreurs de fonction et attendez que toutes les fonctions soient terminées
do1、do2
- fonction test
import ( "fmt" "go.uber.org/multierr" "sync" "testing" ) type Cycle struct { errChan chan error wg sync.WaitGroup } func NewCycle() *Cycle { return &Cycle{ errChan: make(chan error), wg: sync.WaitGroup{}, } } // run fn and collect its error into error channel func (c *Cycle) Run(fn func() error) { c.wg.Add(1) go func() { defer c.wg.Done() if err := fn(); err != nil { c.errChan <- err } }() } // wait all fn finish and combine their error together func (c *Cycle) WaitAllDone() error { var err error go func() { for { if tmpErr, ok := <-c.errChan; ok { err = multierr.Append(err, tmpErr) } else{ break } } }() c.wg.Wait() close(c.errChan) return err } func Do1() error { return fmt.Errorf("ERR1") } func Do2() error { return fmt.Errorf("ERR2") } func Test41(t *testing.T) { c := NewCycle() c.Run(Do1) c.Run(Do2) if err := c.WaitAllDone(); err != nil { t.Log(err) } }
En fin de compte, t.log(err)
génère err1
ou err2
, mais je veux qu'il génère err1 err2
. Pourquoi manque-t-il une erreur. t.log(err)
输出err1
或err2
,但我希望它输出err1 err2
。为什么它会漏掉一个错误。
这是因为 (*cycle).waitalldone
不会等待收集错误的 goroutine 完成。如果您使用 -race
(*cycle).waitalldone
n'attend pas la fin de la goroutine de collecte des erreurs. Si vous exécutez votre code avec l'indicateur -race
, il peut parfois signaler plusieurs erreurs de course aux données. En voici un :
$ go test -race . ================== warning: data race write at 0x00c0000a0610 by goroutine 10: m.(*cycle).waitalldone.func1() /home/zeke/src/temp/76370962/main_test.go:40 +0xb6 previous read at 0x00c0000a0610 by goroutine 7: m.(*cycle).waitalldone() /home/zeke/src/temp/76370962/main_test.go:48 +0x14e m.test41() /home/zeke/src/temp/76370962/main_test.go:63 +0xa4 testing.trunner() /snap/go/current/src/testing/testing.go:1576 +0x216 testing.(*t).run.func1() /snap/go/current/src/testing/testing.go:1629 +0x47
range
Ce changement résoudra le problème :
func (c *cycle) waitalldone() error { var err error + done := make(chan int) go func() { for { if tmperr, ok := <-c.errchan; ok { err = multierr.append(err, tmperr) } else { break } } + close(done) }() c.wg.wait() close(c.errchan) + <-done return err }
func (c *Cycle) WaitAllDone() error { var err error done := make(chan int) go func() { for tmpErr := range c.errChan { err = multierr.Append(err, tmpErr) } close(done) }() c.wg.Wait() close(c.errChan) <-done return err }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!