2017-01-13 6 views
0

Ich verwende einen Ticker, um Aufgaben in regelmäßigen Abständen auszuführen, aber ich habe einige Probleme, wenn Sie es ändern. Ich werde den Ticker beim Empfang einiger Nachrichten in einen neuen ändern und das Intervall ändern. Hier ist der Beispielcode, der das Problem reproduzieren wird:Ändern Sie einen Kanal in wählen Sie {Fall: Kanal}

package main 

import (
    "fmt" 
    "time" 
) 

type A struct { 
    ticker *time.Ticker 
} 

func (a *A) modify() { 
    a.ticker.Stop() 
    a.ticker = time.NewTicker(time.Second) 
} 
func main() { 
    a := new(A) 
    a.ticker = time.NewTicker(time.Second) 
    go func() { 
     for { 
      select { 
      case <-a.ticker.C: 
       fmt.Println("now") 
       go a.modify() 
       /* 
        default: 
         //fmt.Println("default") 
         time.Sleep(time.Millisecond * 100) 
       */ 
      } 
     } 
    }() 
    time.Sleep(time.Second * 60) 
} 

"jetzt" wird nur einmal gedruckt. Aber es wird kontinuierlich gedruckt werden, wenn ich die „go“, wie diese zu entfernen:

package main 

import (
    "fmt" 
    "time" 
) 

type A struct { 
    ticker *time.Ticker 
} 

func (a *A) modify() { 
    a.ticker.Stop() 
    a.ticker = time.NewTicker(time.Second) 
} 
func main() { 
    a := new(A) 
    a.ticker = time.NewTicker(time.Second) 
    go func() { 
     for { 
      select { 
      case <-a.ticker.C: 
       fmt.Println("now") 
       a.modify() 
       /* 
        default: 
         //fmt.Println("default") 
         time.Sleep(time.Millisecond * 100) 
       */ 
      } 
     } 
    }() 
    time.Sleep(time.Second * 60) 
} 

Auch wenn ich die Standard-Klausel unkommentiert lassen, „jetzt“ kann kontinuierlich gedruckt werden. Kann mir jemand erklären, wie das passieren würde?

Antwort

0

Das Problem besteht darin, dass Goroutine asynchron ausgeführt wird. Code verhalten sich so, wenn a.modify() mit:

  1. get tick von a.ticker.C
  2. stoppen alt Ticker und neu erstellen a.ticker.C
  3. warten a.ticker.C mit select

In diesem Fall neu erstellt a.ticker.C in 2. ist identisch mit Kanal wartet in 3.

Wenn Sie 2. in Goroutine. es kann in folgender Reihenfolge

  1. get tick von a.ticker.C
  2. warten a.ticker.Cselect
  3. stoppen alte Ticker mit getan werden, und in 2 warten a.ticker.C

In diesem Fall Kanal neu erstellen. unterscheidet sich von neu erstellten Kanal in 3.. Da die Auswahl eines Channels alt ist und gestoppt wird, wird es nie ein Häkchen bekommen.

Sie können dieses Verhalten durch Einfügen von fmt.Printf bestätigen und auf die Adresse a.ticker.C achten.

func (a *A) modify() { 
    a.ticker.Stop() 
    fmt.Printf("ticker stopped: %p\n", &a.ticker.C) 
    a.ticker = time.NewTicker(time.Second) 
    fmt.Printf("new ticker created: %p\n", &a.ticker.C) 
} 
func main() { 
    a := new(A) 
    a.ticker = time.NewTicker(time.Second) 
    go func() { 
     for { 
      fmt.Printf("waiting for ticker: %p\n", &a.ticker.C) 
      select { 
     .... 

mit a.modify():

waiting for ticker: 0xc420010100 
ticker stopped: 0xc420010100 
new ticker created: 0xc420068000 
waiting for ticker: 0xc420068000 
ticker stopped: 0xc420068000 
new ticker created: 0xc420068080 
waiting for ticker: 0xc420068080 

mit go a.modify():

waiting for ticker: 0xc420010100 
waiting for ticker: 0xc420010100 
ticker stopped: 0xc420010100 
new ticker created: 0xc420066040 

können Sie sehen, dass mit go a.modify() Sie nicht für einen neu erstellten Kanal warten.

UPDATE für das Verhalten von Standard:

Wenn default: mit go a.modify() verwenden, wird es wie folgt verhalten.

  1. warten a.ticker.C, bekam Zecke, go a.modify() nennen, die 3. tut
  2. Warten auf a.ticker.C, hat nichts, so Rückgriff auf Ausfall- und Schlaf 100ms.
  3. stoppen alte Ticker, für a.ticker.Ca.ticker.C
  4. Warte aktualisieren, hat nichts, so Rückgriff auf Ausfall- und Schlaf 100ms.
  5. warten Sie auf a.ticker.C, bekam nichts, so Fallback auf Standard und Schlaf 100ms.
  6. warten Sie auf a.ticker.C, bekam nichts, so Fallback auf Standard und Schlaf 100ms.

.....

  1. Warten auf a.ticker.C, tick wurde, rufen go a.modify()

Der Punkt ist, dass for{} Schleife auch auf dem Gehen halten wenn du nichts von a.ticker.C hast. Sie können das Verhalten mit demselben Code bestätigen.

waiting ticker: 0xc420010100  <-- 1. 
now        <-- 1. 
waiting ticker: 0xc420010100  <-- 2. 
default       <-- 2. 
ticker stopped: 0xc420010100  <-- 3. 
new ticker created: 0xc420066240 <-- 3. 
waiting ticker: 0xc420066240  <-- 4. 
default       <-- 4. 
+0

Verstanden! Warum also der Fall mit dem Default erklärt werden kann –