Reputation: 400
I would hope to execute the "weekly updated" before "daily check" as follows. That means "time.Time" should put "timeChan" immediately rather than do it after waiting for over two seconds when the main function Start running.
And the result should be like this
weekly updated
daily check
daily check
daily check
daily check
weekly updated
daily check
daily check
daily check
daily check
...
Of course,i can just print "weekly updated" firstly one time, but there is have an elegant method?
The code is as follows
package main
import "time"
import "fmt"
func main() {
var a int
timeChan := time.NewTicker(time.Second * 2).C
tickChan := time.NewTicker(time.Millisecond * 500).C
for {
select {
case <-timeChan:
fmt.Println("weekly updated")
a = 1
case <-tickChan:
if a == 1 {
fmt.Println("daily check")
} else {
fmt.Println("Not update?")
}
}
}
}
The result is as follows
Not update?
Not update?
Not update?
weekly updated
daily check
daily check
daily check
daily check
weekly updated
daily check
daily check
daily check
daily check
...
Upvotes: 2
Views: 5393
Reputation: 51
Use a proxy channel?
package main
import (
"fmt"
"time"
)
func main() {
var a int
timeChan := time.NewTicker(time.Second * 2).C
tickChan := time.NewTicker(time.Millisecond * 500).C
// use a proxy channel
proxyChan := make(chan int)
go func() {
// execute the proxy channel immediately
proxyChan <- 0
for {
select {
case <-timeChan:
proxyChan <- 0
}
}
}()
for {
select {
case <-proxyChan: // use proxyChan rather than timeChan
fmt.Println("weekly updated")
a = 1
case <-tickChan:
if a == 1 {
fmt.Println("daily check")
} else {
fmt.Println("Not update?")
}
}
}
}
And you can abstract it like this:
package main
import (
"fmt"
"time"
)
func main() {
var a int
// use like this
timeChan, callback := NewProxyTicker(time.Second * 2)
go callback()
tickChan := time.NewTicker(time.Millisecond * 500).C
for {
select {
case <-timeChan:
fmt.Println("weekly updated")
a = 1
case <-tickChan:
if a == 1 {
fmt.Println("daily check")
} else {
fmt.Println("Not update?")
}
}
}
}
func NewProxyTicker(d time.Duration) (chan time.Time, func()) {
ticker := time.NewTicker(d)
proxyChan := make(chan time.Time)
callback := func() {
proxyChan <- time.Now()
for {
select {
case <-ticker.C:
proxyChan <- time.Now()
}
}
}
return proxyChan, callback
}
Upvotes: 1
Reputation: 1
If the purpose of the for statement is to only trigger that one function/task at an interval, you can place the work logic before the select statement and then use the cases to trigger the for loop to cycle. This will cause the work logic to run on entry into the loop.
I don't know the structure of your team's project, so if your select statement has many other cases not meant as triggers, then this wouldn't work.
package main
import (
"context"
"log"
"os"
"os/signal"
"time"
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
weeklyTicker := time.NewTicker(2 * time.Second)
dailyTicker := time.NewTicker(10 * time.Second)
customTrigger := make(chan struct{})
// Example of custom trigger at a random point
go func() {
time.Sleep(5 * time.Second)
customTrigger <- struct{}{}
}()
weeklyRun := true
for {
if weeklyRun {
log.Println("Run weekly logic")
weeklyRun = false
} else {
log.Println("Run daily logic")
}
select {
case <-ctx.Done():
log.Println("interrupt received")
return
case <-dailyTicker.C:
log.Println("weekly updated")
weeklyRun = true
case <-weeklyTicker.C:
log.Println("daily check")
case <-customTrigger:
log.Println("custom check trigger")
}
}
}
Output:
2022/12/22 13:52:12 Run weekly logic
2022/12/22 13:52:14 daily check
2022/12/22 13:52:14 Run daily logic
2022/12/22 13:52:16 daily check
2022/12/22 13:52:16 Run daily logic
2022/12/22 13:52:17 custom check trigger
2022/12/22 13:52:17 Run daily logic
2022/12/22 13:52:18 daily check
2022/12/22 13:52:18 Run daily logic
2022/12/22 13:52:20 daily check
2022/12/22 13:52:20 Run daily logic
2022/12/22 13:52:22 daily check
2022/12/22 13:52:22 Run daily logic
2022/12/22 13:52:22 weekly updated
2022/12/22 13:52:22 Run weekly logic
^C2022/12/22 13:52:23 interrupt received
Upvotes: 0
Reputation: 46403
Just put the work in a function and call it.
var a int
timeChan := time.NewTicker(time.Second * 2).C
tickChan := time.NewTicker(time.Millisecond * 500).C
f := func() {
fmt.Println("weekly updated")
a = 1
}
f()
for {
select {
case <-timeChan:
f()
case <-tickChan:
if a == 1 {
fmt.Println("daily check")
} else {
fmt.Println("Not update?")
}
}
}
Upvotes: 1
Reputation: 13806
Set your Ticker for weekly
at first time.Millisecond
. Then change it, when 1st time it is done.
package main
import (
"fmt"
"time"
)
func main() {
var a = 0
ticker := time.NewTicker(1)
timeChan := ticker.C
tickChan := time.NewTicker(time.Millisecond * 500).C
for {
select {
case <-timeChan:
fmt.Println("weekly updated")
if a == 0 {
ticker.Stop()
timeChan = time.NewTicker(time.Second * 2).C
}
a = 1
case <-tickChan:
if a == 1 {
fmt.Println("daily check")
} else {
fmt.Println("Not update?")
}
default:
}
}
}
Output:
weekly updated
daily check
daily check
daily check
daily check
weekly updated
Upvotes: 3