Eine praktische Anleitung zu Go’s Timer und Ticker
Olivia Novak
Dev Intern · Leapcell

Vorwort
In der täglichen Entwicklung können wir auf Situationen stoßen, in denen wir die Ausführung einiger Aufgaben verzögern oder sie regelmäßig ausführen müssen. An diesem Punkt müssen wir Timer in Go verwenden.
In Go gibt es zwei Arten von Timern: time.Timer
(Einmal-Timer) und time.Ticker
(periodischer Timer). Dieser Artikel stellt beide Arten von Timern vor.
Timer: Einmal-Timer
Ein Timer ist ein Einmal-Timer, der verwendet wird, um eine Operation einmal zu einem bestimmten Zeitpunkt in der Zukunft auszuführen.
Grundlegende Verwendung
Es gibt zwei Möglichkeiten, einen Timer zu erstellen:
NewTimer(d Duration) *Timer
: Diese Funktion akzeptiert einen Parameterd
vom Typtime.Duration
(das Zeitintervall), der angibt, wie lange der Timer warten soll, bevor er abläuft.NewTimer
gibt einen neuen Timer zurück, der intern einen KanalC
verwaltet. Wenn der Timer ausgelöst wird, wird die aktuelle Zeit an den KanalC
gesendet.AfterFunc(d Duration, f func()) *Timer
: Akzeptiert ein angegebenes Zeitintervalld
und eine Callback-Funktionf
. Diese Funktion gibt einen neuen Timer zurück, und wenn der Timer abläuft, ruft er direktf
auf, anstatt ein Signal über den KanalC
zu senden. Durch Aufrufen derStop
-Methode des Timers kann der Timer gestoppt und die Ausführung vonf
abgebrochen werden.
Der folgende Code demonstriert, wie man NewTimer
und AfterFunc
verwendet, um Timer zu erstellen und deren grundlegende Verwendung:
package main import ( "fmt" "time" ) func main() { // Erstellen eines Timers mit NewTimer timer := time.NewTimer(time.Second) go func() { select { case <-timer.C: fmt.Println("timer fired!") } }() // Erstellen eines weiteren Timers mit AfterFunc time.AfterFunc(time.Second, func() { fmt.Println("timer2 fired!") }) // Main-Goroutine wartet 2 Sekunden, um sicherzustellen, dass wir die Timer-Ausgabe sehen time.Sleep(time.Second * 2) }
Die Ausgabe des obigen Codes ist wie folgt:
timer fired! timer2 fired!
Hier ist eine schrittweise Erklärung des Codes:
- Verwenden Sie
NewTimer
, um einen Timer zu erstellen, und lauschen Sie dann auf seineC
-Eigenschaft in einer neuen Goroutine, um darauf zu warten, dass der Timer ausgelöst wird. - Verwenden Sie
AfterFunc
, um einen weiteren Timer zu erstellen, und geben Sie eine Callback-Funktion an, um das Timer-Ablaufereignis zu behandeln. - Die Main-Goroutine wartet lange genug, um sicherzustellen, dass die Auslöseinformationen des Timers ausgegeben werden können.
Methodendetails
Reset
Reset(d Duration) bool
: Diese Methode wird verwendet, um die Ablaufzeit eines Timers zurückzusetzen, wodurch er im Wesentlichen reaktiviert wird. Sie akzeptiert einen Parameter d
vom Typ time.Duration
, der angibt, wie lange der Timer warten soll, bevor er abläuft.
Darüber hinaus gibt diese Methode einen bool
-Wert zurück:
- Wenn der Timer aktiv ist, gibt er
true
zurück. - Wenn der Timer bereits abgelaufen oder gestoppt wurde, gibt er
false
zurück (Hinweis:false
bedeutet nicht, dass das Zurücksetzen fehlgeschlagen ist, sondern gibt nur den aktuellen Status des Timers an).
Hier ist ein Codebeispiel:
package main import ( "fmt" "time" ) func main() { timer := time.NewTimer(5 * time.Second) // Erstes Zurücksetzen: Der Timer ist aktiv, also wird true zurückgegeben b := timer.Reset(1 * time.Second) fmt.Println(b) // true second := time.Now().Second() select { case t := <-timer.C: fmt.Println(t.Second() - second) // 1s } // Zweites Zurücksetzen: Der Timer ist bereits abgelaufen, also wird false zurückgegeben b = timer.Reset(2 * time.Second) fmt.Println(b) // false second = time.Now().Second() select { case t := <-timer.C: fmt.Println(t.Second() - second) // 2s } }
Die Ausgabe des Codes ist wie folgt:
true 1 false 2
Schrittweise Erklärung:
- Erstellen Sie einen Timer, der nach 5 Sekunden ablaufen soll.
- Rufen Sie sofort die
Reset
-Methode auf, um ihn so einzustellen, dass er in 1 Sekunde abläuft. Da der Timer noch aktiv ist (nicht abgelaufen), gibtReset
true
zurück. - Die
select
-Anweisung wartet darauf, dass der Timer abläuft, und gibt die tatsächlich verstrichenen Sekunden aus (ca. 1 Sekunde). - Der Timer wird erneut zurückgesetzt, diesmal so, dass er in 2 Sekunden abläuft. Da der Timer bereits abgelaufen ist, gibt
Reset
false
zurück. - Die
select
-Anweisung wartet erneut darauf, dass der Timer abläuft, und gibt die verstrichenen Sekunden aus (ca. 2 Sekunden).
Stop
Stop() bool
: Diese Methode wird verwendet, um den Timer zu stoppen. Wenn der Timer erfolgreich gestoppt wurde, gibt sie true
zurück. Wenn der Timer bereits abgelaufen oder gestoppt wurde, gibt sie false
zurück. Hinweis: Die Stop
-Operation schließt den Kanal C
nicht.
Hier ist ein Codebeispiel:
package main import ( "fmt" "time" ) func main() { timer := time.NewTimer(3 * time.Second) // Stoppen Sie den Timer, bevor er ausgelöst wird, also wird true zurückgegeben stop := timer.Stop() fmt.Println(stop) // true stop = timer.Stop() // Stoppen Sie den Timer erneut, da er bereits gestoppt wurde, wird false zurückgegeben fmt.Println(stop) // false }
Die Ausgabe ist wie folgt:
true false
Schrittweise Erklärung:
- Erstellen Sie einen Timer, der nach 3 Sekunden ausgelöst werden soll.
- Rufen Sie sofort die
Stop
-Methode auf, um den Timer zu stoppen. Da der Timer noch nicht ausgelöst wurde, gibtStop
true
zurück. - Rufen Sie
Stop
erneut auf, um zu versuchen, denselben Timer zu stoppen. Da er bereits gestoppt ist, gibtStop
diesmalfalse
zurück.
Ticker: Periodischer Timer
Ein Ticker ist ein periodischer Timer, der verwendet wird, um Aufgaben wiederholt in festen Intervallen auszuführen. In jedem Intervall sendet er die aktuelle Zeit an seinen Kanal.
Grundlegende Verwendung
Wir können die Funktion NewTicker
verwenden, um ein neues Ticker-Objekt zu erstellen. Diese Funktion akzeptiert einen Parameter time.Duration
d
(das Intervall).
Hier ist ein Beispiel:
package main import ( "context" "fmt" "time" ) func main() { ticker := time.NewTicker(time.Second) defer ticker.Stop() timeout, cancelFunc := context.WithTimeout(context.Background(), time.Second*5) defer cancelFunc() go func() { for { select { case <-timeout.Done(): fmt.Println("timeout done") return case <-ticker.C: fmt.Println("ticker fired!") } } }() // Main-Goroutine wartet 7 Sekunden, um sicherzustellen, dass wir die Timer-Ausgaben sehen time.Sleep(time.Second * 7) }
Die Ausgabe des Codes ist wie folgt:
ticker fired! ticker fired! ticker fired! ticker fired! ticker fired! timeout done
Schrittweise Erklärung:
- Erstellen Sie einen Timer, der jede Sekunde ausgelöst wird. Um sicherzustellen, dass der Timer am Ende der Funktion bereinigt wird, verwenden wir
defer ticker.Stop()
. - Erstellen Sie einen Kontext, der nach 5 Sekunden abläuft.
cancelFunc
wird verwendet, um den Kontext vor dem Beenden zu bereinigen. - In einer neuen Goroutine überwacht eine
select
-Anweisung zwei Kanäle: den Kanal des Timers (ticker.C
) und den Done-Kanal des Kontexts (timeout.Done()
). Wenn der Timer jede Sekunde ausgelöst wird, gibt er eine Nachricht aus. Wenn der Kontext abläuft (nach 5 Sekunden), gibt er eine Timeout-Meldung aus und kehrt zurück, wodurch die Goroutine beendet wird. - Die Main-Goroutine verwendet
time.Sleep(time.Second * 7)
, um 7 Sekunden zu warten, wodurch sichergestellt wird, dass sowohl das Auslösen des Timers als auch die Timeout-Ereignisse beobachtet werden können.
Zusätzlich zum Abhören von ticker.C
mit select
können Sie auch eine for range
-Schleife verwenden:
for range ticker.C {}
Hinweis: Selbst wenn Sie einen Ticker mit der Stop
-Methode stoppen, wird sein Kanal C
nicht geschlossen. Dies bedeutet, dass Sie, egal ob Sie for select
oder for range
verwenden, um ticker.C
abzuhören, einen anderen Mechanismus benötigen, um die Schleife zu verlassen, z. B. die Verwendung eines Kontexts.
Methodendetails
Reset
Die Methode Reset(d Duration)
wird verwendet, um den Ticker zu stoppen und seine Periode auf die angegebene Dauer zurückzusetzen. Der nächste Tick tritt ein, nachdem die neue Periode abgelaufen ist. Sie akzeptiert einen Parameter d
vom Typ time.Duration
, der das neue Intervall darstellt. Dieser Parameter muss größer als Null sein; andernfalls löst die Methode Reset
intern eine Panic aus.
Hier ist ein Beispiel:
package main import ( "time" ) func main() { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() // Reset the ticker ticker.Reset(1 * time.Second) second := time.Now().Second() for t := range ticker.C { // 1s fmt.Printf("Interval: %d seconds", t.Second()-second) break } }
Die Ausgabe des Codes ist wie folgt:
Interval: 1 seconds
Schrittweise Erklärung:
- Erstellen Sie einen time.Ticker, der alle 5 Sekunden ausgelöst wird.
- Verwenden Sie die
Reset
-Methode, um das Intervall von 5 Sekunden auf 1 Sekunde zu ändern. - Geben Sie in einer einzelnen Schleife das Intervall aus. Das erwartete Ergebnis ist 1 Sekunde.
Stop
Die Methode Stop()
wird verwendet, um den Ticker zu stoppen. Nach dem Aufruf von Stop
werden keine weiteren Ticks an den Kanal C
gesendet. Hinweis: Die Stop
-Operation schließt den Kanal C
nicht.
Hier ist ein Beispiel:
package main import ( "fmt" "time" ) func main() { ticker := time.NewTicker(time.Second) quit := make(chan struct{}) // Create a quit channel go func() { for { select { case <-ticker.C: fmt.Println("Ticker fired!") case <-quit: fmt.Println("Goroutine stopped!") return // Exit the loop when receiving the quit signal } } }() time.Sleep(time.Second * 3) ticker.Stop() // Stop the ticker close(quit) // Send the quit signal fmt.Println("Ticker stopped!") }
Die Ausgabe ist wie folgt:
Ticker fired! Ticker fired! Ticker fired! Goroutine stopped! Ticker stopped!
- Erstellen Sie ein time.Ticker-Objekt, das jede Sekunde ausgelöst wird. Gleichzeitig wird ein Quit-Kanal vom Typ
chan struct{}
eingeführt, der verwendet wird, um ein Stoppsignal an die laufende Goroutine zu senden. - Starten Sie eine neue Goroutine. In dieser Goroutine überwacht eine For-Select-Schleife zwei Ereignisse: das Auslösen des Tickers (
case <-ticker.C
) und das Quit-Signal (case <-quit
). Jedes Mal, wenn der Ticker ausgelöst wird, gibt er eine Meldung aus. Wenn er das Quit-Signal empfängt, gibt er eine Meldung aus und verlässt die Schleife. - In der Main-Goroutine simuliert
time.Sleep(time.Second * 3)
eine Wartezeit von 3 Sekunden, während der der Ticker einige Male ausgelöst wird. - Die Main-Goroutine stoppt den Ticker durch Aufrufen von
Stop
und schließt dann den Quit-Kanal. Die Goroutine empfängt das Quit-Signal, gibt eine Meldung aus und verlässt die Schleife.
Die Stop
-Methode schließt den Kanal C
nicht, daher müssen wir andere Mittel (z. B. ein Quit-Signal) verwenden, um Ressourcen zu bereinigen.
Hauptunterschiede zwischen Timer und Ticker
Verwendung:
- Timer wird für Aufgaben verwendet, die nach einer einzelnen Verzögerung ausgeführt werden.
- Ticker wird für Aufgaben verwendet, die wiederholt ausgeführt werden müssen.
Verhaltensmerkmale:
- Timer wird einmal nach der angegebenen Verzögerung ausgelöst und sendet einen einzelnen Zeitwert an seinen Kanal.
- Ticker wird regelmäßig im angegebenen Intervall ausgelöst und sendet wiederholte Zeitwerte an seinen Kanal.
Steuerbarkeit:
- Timer kann zurückgesetzt (
Reset
-Methode) und gestoppt werden (Stop
-Methode).Reset
wird verwendet, um die Auslösezeit des Timers zu ändern. - Ticker kann auch zurückgesetzt (
Reset
-Methode) und gestoppt werden (Stop
-Methode).Reset
wird verwendet, um das Intervall zu ändern, in dem der Ticker ausgelöst wird.
Beendigungsvorgang:
- Die
Stop
-Methode von Timer wird verwendet, um zu verhindern, dass der Timer ausgelöst wird. Wenn der Timer bereits ausgelöst wurde, entferntStop
nicht den Zeitwert, der bereits an seinen Kanal gesendet wurde. - Die
Stop
-Methode von Ticker wird verwendet, um das periodische Auslösen zu stoppen. Nach dem Stoppen werden keine neuen Werte mehr an seinen Kanal gesendet.
Hinweise
- Für sowohl Timer als auch Ticker schließt der Aufruf der
Stop
-Methode ihreC
-Kanäle nicht. Wenn andere Goroutinen auf diesem Kanal lauschen, müssen Sie diese Goroutinen manuell beenden, um potenzielle Speicherlecks zu vermeiden. Normalerweise kann eine solche Ressourcenbereinigung mithilfe einescontext
oder durch ein Quit-Signal (implementiert mit Kanälen) behandelt werden. - Nachdem ein Ticker seine Aufgabe abgeschlossen hat, sollten Sie die Methode
Stop
aufrufen, um die zugehörigen Ressourcen freizugeben und Speicherlecks zu vermeiden. Wenn Sie den Ticker nicht rechtzeitig stoppen, kann dies zu einer kontinuierlichen Ressourcenbelegung führen.
Zusammenfassung
Dieser Artikel hat Go's Timer und Ticker eingehend untersucht und detailliert vorgestellt, wie man sie erstellt, ihre grundlegende Verwendung und ihre zugehörigen Methoden. Darüber hinaus fasst der Artikel die Hauptunterschiede zwischen diesen beiden Arten von Timern zusammen und hebt die Überlegungen hervor, die bei ihrer Verwendung beachtet werden sollten.
Beim Schreiben von Go-Code sollten Sie den geeigneten Timer entsprechend dem Anwendungsszenario auswählen. Gleichzeitig ist es wichtig, Best Practices zu befolgen – insbesondere Ressourcen nach dem Beenden mit einem Timer unverzüglich freizugeben – was entscheidend ist, um potenzielle Speicherlecks zu vermeiden.
Wir sind Leapcell, Ihre erste Wahl für das Hosting von Go-Projekten.
Leapcell ist die Next-Gen Serverless Platform für Webhosting, asynchrone Aufgaben und Redis:
Multi-Language Support
- Entwickeln Sie mit Node.js, Python, Go oder Rust.
Stellen Sie unbegrenzt Projekte kostenlos bereit
- Zahlen Sie nur für die Nutzung – keine Anfragen, keine Gebühren.
Unschlagbare Kosteneffizienz
- Pay-as-you-go ohne Leerlaufgebühren.
- Beispiel: 25 $ unterstützen 6,94 Millionen Anfragen bei einer durchschnittlichen Antwortzeit von 60 ms.
Optimierte Entwicklererfahrung
- Intuitive Benutzeroberfläche für mühelose Einrichtung.
- Vollautomatische CI/CD-Pipelines und GitOps-Integration.
- Echtzeitmetriken und -protokollierung für umsetzbare Einblicke.
Mühelose Skalierbarkeit und hohe Leistung
- Automatische Skalierung zur einfachen Bewältigung hoher Parallelität.
- Kein Betriebsaufwand – konzentrieren Sie sich einfach auf den Aufbau.
Erfahren Sie mehr in der Dokumentation!
Folgen Sie uns auf X: @LeapcellHQ