mirror of
https://github.com/teivah/100-go-mistakes.git
synced 2026-06-21 00:47:11 +08:00
Merge pull request #73 from wureny/patch-1
Write summary for mistake 76
This commit is contained in:
commit
3e32497d21
1 changed files with 62 additions and 0 deletions
|
|
@ -1756,6 +1756,68 @@ ticker = time.NewTicker(1000 * time.Nanosecond)
|
|||
???+ info "TL;DR"
|
||||
|
||||
Avoiding calls to `time.After` in repeated functions (such as loops or HTTP handlers) can avoid peak memory consumption. The resources created by `time.After` are released only when the timer expires.
|
||||
People often use time.After in loops or HTTP handlers repeatedly to implement the timing function. But it can lead to unintended peak memory consumption due to the delayed release of resources, just like the following code:
|
||||
|
||||
```go
|
||||
func consumer1(ch <-chan Event) {
|
||||
for {
|
||||
select {
|
||||
case event := <-ch:
|
||||
handle(event)
|
||||
case <-time.After(time.Hour):
|
||||
log.Println("warning: no messages received")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The source code of the function time.After is as follows:
|
||||
|
||||
```go
|
||||
func After(d Duration) <-chan Time {
|
||||
return NewTimer(d).C
|
||||
}
|
||||
```
|
||||
|
||||
As we see, it returns receive-only channel.
|
||||
|
||||
When time.After is used in a loop or repeated context, a new channel is created in each iteration. If these channels are not properly closed or if their associated timers are not stopped, they can accumulate and consume memory. The resources associated with each timer and channel are only released when the timer expires or the channel is closed.
|
||||
|
||||
To avoid this happening, We can use context's timeout setting instead of time.After, like below:
|
||||
|
||||
```go
|
||||
func consumer2(ch <-chan Event) {
|
||||
for {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
|
||||
select {
|
||||
case event := <-ch:
|
||||
cancel()
|
||||
handle(event)
|
||||
case <-ctx.Done():
|
||||
log.Println("warning: no messages received")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We can also use time.NewTimer like below:
|
||||
|
||||
```go
|
||||
func consumer3(ch <-chan Event) {
|
||||
timerDuration := 1 * time.Hour
|
||||
timer := time.NewTimer(timerDuration)
|
||||
|
||||
for {
|
||||
timer.Reset(timerDuration)
|
||||
select {
|
||||
case event := <-ch:
|
||||
handle(event)
|
||||
case <-timer.C:
|
||||
log.Println("warning: no messages received")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[Source code :simple-github:](https://github.com/teivah/100-go-mistakes/tree/master/src/10-standard-lib/76-time-after/main.go)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue