2016-08-29 1 views
2

Ich versuche, einen einfachen Code von Golang Routinen zu verstehen:Wie kann ich "time.After" und "default" in Golang verwenden?

package main 

import (
    "fmt" 
    "time" 
) 

func sleep(seconds int, endSignal chan<- bool) { 
    time.Sleep(time.Duration(seconds) * time.Second) 
    endSignal <- true 
} 

func main() { 
    endSignal := make(chan bool, 1) 
    go sleep(3, endSignal) 
    var end bool 

    for !end { 
     select { 
     case end = <-endSignal: 
      fmt.Println("The end!") 
     case <-time.After(5 * time.Second): 
      fmt.Println("There's no more time to this. Exiting!") 
      end = true 
     } 
    } 

} 

ist das in Ordnung, aber warum kann ich nicht eine einfache Standard in diesem „wählen Sie“ Block verwenden? Etwas wie folgt aus:

for !end { 
    select { 
    case end = <-endSignal: 
     fmt.Println("The end.") 
    case <-time.After(4 * time.Second): 
     fmt.Println("There's no more time to this. Exiting!") 
     end = true 
    default: 
     fmt.Println("No end signal received.") 
    } 
} 

Es wird diese Ausgabe:

❯ go run goroutines-timeout.go 
No end signal received! 
No end signal received! 
No end signal received! 
No end signal received! 
... 
The end! 

Und ich, warum nicht verstehen kann.

+0

Diese jede Iteration überprüft ist, was 'default 'tut. Kannst du erklären, was du erwartet hast? – JimB

+0

Ich erwarte, dass "default" dies tut, während die "time.After" Zeit nicht endet. –

+0

Ich verstehe nicht, das ist was es tut. Der Fall 'time.After' wird nicht ausgeführt, da der Standardfall verwendet wird. – JimB

Antwort

3

Jedes Mal, wenn Sie time.After(4 * time.Second) ausführen, erstellen Sie einen neuen Timer-Kanal. Es gibt keine Möglichkeit, dass sich die select-Anweisung an den Kanal erinnern kann, für den sie in der vorherigen Iteration ausgewählt wurde. Sie haben auch eine asynchrone Operation ausgeführt und diese in eine "busy loop" umgewandelt, die den Zweck der select-Anweisung zunichte gemacht hat.

Alles, was Sie brauchen, ist eine einfache Auswahl um die zwei Kanäle, die Sie interessiert sind. Es muss überhaupt keine Schleife.

select { 
case <-endSignal: 
    fmt.Println("The end!") 
case <-time.After(4 * time.Second): 
    fmt.Println("There's no more time to this. Exiting!") 
} 

https://play.golang.org/p/jb4EE8e6cw

Wenn Sie wirklich mehrere Male abfragen wollen, stellen Sie den Timer außerhalb der von for-Schleife, so dass die gleiche

timeout := time.After(5 * time.Second) 
pollInt := time.Second 

for { 
    select { 
    case <-endSignal: 
     fmt.Println("The end!") 
     return 
    case <-timeout: 
     fmt.Println("There's no more time to this. Exiting!") 
     return 
    default: 
     fmt.Println("still waiting") 
    } 
    time.Sleep(pollInt) 
} 
+0

Danke, ich habe es jetzt –

Verwandte Themen