Heim >Backend-Entwicklung >Golang >Stoppen Sie eine Goroutine, die auf unbestimmte Zeit in einen Kanal schreibt

Stoppen Sie eine Goroutine, die auf unbestimmte Zeit in einen Kanal schreibt

WBOY
WBOYnach vorne
2024-02-05 23:09:07938Durchsuche

停止无限期写入通道的 goroutine

Frageninhalt

Ich habe eine Funktion, die eine Goroutine erstellt, die einen Kanal auf unbestimmte Zeit füllt, zum Beispiel:

func foo() <-chan int {
  ch := make(chan int) 
  go func() {
    defer close(ch)
    for {
      ch <- 1
    } 
  }() 
  return ch
}

Angenommen, wir haben einen Verbraucher, den wir nach einer bestimmten Zeit stoppen möchten:

ch:=foo() 
<-ch
<-ch
// done

Jetzt möchte ich Goroutine-Ressourcen bereinigen, einschließlich Kanälen. Ich habe versucht, dafür einen „Abschluss“-Kanal hinzuzufügen, bin dann aber in eine Sackgasse geraten:

func Foo() (<-chan int, chan<- bool) {
  ch := make(chan int)
  done := make(chan bool)
  go func() {
    defer close(ch)
    for {
      select {
      case <-done:
          return
      default:
          ch <- 1
      }
    } 
  }() 
  return ch, done
}

func main() {
  ch, done := Foo()
  <-ch
  <-ch
  done <- true
  // HERE
}

Jetzt scheint es zu funktionieren, aber nur, weil das Programm beendet wird, wenn ich es durch einige io-Operationen ersetze // here(例如:http.get(“http://google.com”)) ,我面临死锁(fatal 错误:所有 goroutine 都在睡觉 - 死锁!). Ich frage mich, ob es eine andere Möglichkeit gibt, die von der Funktion foo generierten Goroutinen und Kanäle zu bereinigen. foo 函数创建的生成的 goroutine 和通道。


正确答案


只需在启动的 goroutine 中将 default 替换为 case

Richtige Antwort

defaultErsetzen Sie einfach

durch case in der Start-Goroutine:
    func Foo() (<-chan int, chan<- bool) {
      ch := make(chan int)
      done := make(chan bool)
      go func() {
        defer close(ch)
        for {
          select {
          case <-done:
              return
          case ch <- 1:
          }
        } 
      }() 
      return ch, done
    }
    
  • Der Grund, warum der ursprüngliche Code in der done 通道时,启动的写入 ch 通道的 goroutines 会立即转到 default 情况。然后 goroutine 会阻塞在 ch <- 1 行,直到其他 goroutine 从 ch-Situation blockiert ist, ist wie folgt:
  • ch 读取两次。这会导致在启动的 goroutine 处有两个成功的执行循环。然后它尝试写入 done。此时启动的goroutine可能已经检查了select语句,陷入default情况并阻塞在ch <- 1行。因此主 goroutine 也会无限期地阻塞在 done <- trueEine Goroutine, die das Schreiben in einen ch-Kanal initiiert hat, geht sofort in den
  • -Fall über, wenn keine anderen gleichzeitig laufenden Goroutinen in den done-Kanal schreiben. Die Goroutine blockiert dann die Zeile ch <- 1, bis eine andere Goroutine den Wert von ch liest.
🎜Die Hauptcoroutine liest zweimal aus ch. Dies führt zu zwei erfolgreichen Ausführungsschleifen bei der gestarteten Goroutine. Anschließend wird versucht, done zu schreiben. Die zu diesem Zeitpunkt gestartete Goroutine hat möglicherweise die select-Anweisung überprüft, ist in die 🎜-Situation geraten und hat an der Zeile ch <- 1 blockiert. Daher blockiert die Haupt-Goroutine auch auf unbestimmte Zeit die Zeile done <- true. Dies kann zu einem Deadlock führen. 🎜 🎜

Das obige ist der detaillierte Inhalt vonStoppen Sie eine Goroutine, die auf unbestimmte Zeit in einen Kanal schreibt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen