How to pause and resume goroutine? - go

I am trying to pause and resume groutine. I understand I can sleep the run, but I am looking for is like a button "pause/resume" rather than a timer.
Here is my attempt. I am using the blocking feature of channel to pause, and select to switch what to execute based on channel value. However, the output is always Running in my case.
func main() {
ctx := wctx{}
go func(ctx wctx) {
for {
time.Sleep(1 * time.Second)
select {
case <-ctx.pause:
fmt.Print("Paused")
<-ctx.pause
case <-ctx.resume:
fmt.Print("Resumed")
default:
fmt.Print("Running \n")
}
}
}(ctx)
ctx.pause <- struct{}{}
ctx.resume <- struct{}{}
}
type wctx struct {
pause chan struct{}
resume chan struct{}
}

A select with multiple ready cases chooses one pseudo-randomly. So if the goroutine is "slow" to check those channels, you might send a value on both pause and resume (assuming they are buffered) so receiving from both channels could be ready, and resume could be chosen first, and in a later iteration the pause when the goroutine should not be paused anymore.
For this you should use a "state" variable synchronized by a mutex. Something like this:
const (
StateRunning = iota
StatePaused
)
type wctx struct {
mu sync.Mutex
state int
}
func (w *wctx) SetState(state int) {
w.mu.Lock()
defer w.mu.Unlock()
w.state = state
}
func (w *wctx) State() int {
w.mu.Lock()
defer w.mu.Unlock()
return w.state
}
Testing it:
ctx := &wctx{}
go func(ctx *wctx) {
for {
time.Sleep(1 * time.Millisecond)
switch state := ctx.State(); state {
case StatePaused:
fmt.Println("Paused")
default:
fmt.Println("Running")
}
}
}(ctx)
time.Sleep(3 * time.Millisecond)
ctx.SetState(StatePaused)
time.Sleep(3 * time.Millisecond)
ctx.SetState(StateRunning)
time.Sleep(2 * time.Millisecond)
Output (try it on the Go Playground):
Running
Running
Running
Paused
Paused
Paused
Running
Running

You need to initialize your channels, remember that reads from nil channels always blocks.
A select with a default case never blocks.
Here is a modified version of your program, that fixes the above mentioned issues:
package main
import (
"fmt"
"time"
)
func main() {
ctx := wctx{
pause: make(chan struct{}),
resume: make(chan struct{}),
}
go func(ctx wctx) {
for {
select {
case <-ctx.pause:
fmt.Println("Paused")
case <-ctx.resume:
fmt.Println("Resumed")
}
fmt.Println("Running")
time.Sleep(time.Second)
}
}(ctx)
ctx.pause <- struct{}{}
ctx.resume <- struct{}{}
}
type wctx struct {
pause chan struct{}
resume chan struct{}
}

Related

Go send and receive with buffered channel

i'm trying to implement a pipeline using buffered channel with size one, it will accept incoming message, print it out and wait some time then pass it forward. The main problem is that reading gobyexample tutorial I decided to implement it using select statement, but I cannot figure out how to make channel block until it will pass the message forward.
func runVertex(vertex Vertex) {
newVertex := findVertex(vertex)
var packet handledPacket
for {
select {
case packet.packet = <-someChannel:
fmt.Println("msg received")
time.Sleep(time.Second)
case someOtherChannel <- packet.packet:
time.Sleep(time.Second)
default:
time.Sleep(10 * time.Millisecond)
}
}
}
You don't need a select to do the thing you described:
for {
packet.packet =<- someChannel:
fmt.Println("msg received");
time.Sleep(time.Second);
someOtherChannel<-packet.packet:
}
The operation of receiving something from a channel is blocking, you don't need to do something special. And selects are intended to let you either handle multiple channels or somehow react if there is nothing new in the channel(s) you are watching. Here is an example:
package main
import (
"fmt"
"time"
)
func messagesPrinter(channel1 chan string, channel2 chan string) {
var message string
for {
select {
case message = <-channel1:
fmt.Println("A message from channel 1:", message)
time.Sleep(time.Second)
case message = <-channel2:
fmt.Println("A message from channel 2:", message)
time.Sleep(time.Second)
default: // Optional part
fmt.Println("Now message yet...")
time.Sleep(500 * time.Millisecond)
}
}
}
func main() {
c1 := make(chan string)
c2 := make(chan string)
go messagesPrinter(c1, c2)
c1 <- "Hello"
c1 <- "How are you?"
time.Sleep(5 * time.Second)
c2 <- "I'm fine!"
}

Running multiple methods periodically

I'm new to go and trying to make two methods run at the same time periodically for as long at the application is running. I've managed to come up with the following but the for true part does not feel right as this is blocking.
Would channels be a better way todo this? Any pointers in the right direction would be helpful.
func main() {
t1 := schedule(ping, time.Second)
t2 := schedule(ping, 2*time.Second)
for true {
time.Sleep(1 * time.Second)
}
t1.Stop()
t2.Stop()
}
func schedule(f func(interval time.Duration), interval time.Duration) *time.Ticker {
ticker := time.NewTicker(interval)
go func() {
for range ticker.C {
f(interval)
}
}()
return ticker
}
func ping(interval time.Duration) {
log.Println("ping ", interval)
}
To prevent the application from exiting, the main goroutine must block.
Use select {} to block the main goroutine.
Because the tickers run for the duration of the application, there's no need to stop the tickers.
func main() {
schedule(ping, time.Second)
schedule(ping, 2*time.Second)
select {}
}

Reading from map with locks doesn't return value via channel

I tried to implement a locking version of reading/writing from a map in golang, but it doesn't return the desired result.
package main
import (
"sync"
"fmt"
)
var m = map[int]string{}
var lock = sync.RWMutex{}
func StoreUrl(id int, url string) {
for {
lock.Lock()
defer lock.Unlock()
m[id] = url
}
}
func LoadUrl(id int, ch chan string) {
for {
lock.RLock()
defer lock.RUnlock()
r := m[id]
ch <- r
}
}
func main() {
go StoreUrl(125, "www.google.com")
chb := make(chan string)
go LoadUrl(125, chb);
C := <-chb
fmt.Println("Result:", C)
}
The output is:
Result:
Meaning the value is not returned via the channel, which I don't get. Without the locking/goroutines it seems to work fine. What did I do wrong?
The code can also be found here:
https://play.golang.org/p/-WmRcMty5B
Infinite loops without sleep or some kind of IO are always bad idea.
In your code if you put a print statement at the start of StoreUrl, you will find that it never gets printed i.e the go routine was never started, the go call is setting putting the info about this new go routine in some run queue of the go scheduler but the scheduler hasn't ran yet to schedule that task. How do you run the scheduler? Do sleep/IO/channel reading/writing.
Another problem is that your infinite loop is taking lock and trying to take the lock again, which will cause it to deadlock. Defer only run after function exit and that function will never exit because of infinite loop.
Below is modified code that uses sleep to make sure every execution thread gets time to do its job.
package main
import (
"sync"
"fmt"
"time"
)
var m = map[int]string{}
var lock = sync.RWMutex{}
func StoreUrl(id int, url string) {
for {
lock.Lock()
m[id] = url
lock.Unlock()
time.Sleep(1)
}
}
func LoadUrl(id int, ch chan string) {
for {
lock.RLock()
r := m[id]
lock.RUnlock()
ch <- r
}
}
func main() {
go StoreUrl(125, "www.google.com")
time.Sleep(1)
chb := make(chan string)
go LoadUrl(125, chb);
C := <-chb
fmt.Println("Result:", C)
}
Edit: As #Jaun mentioned in the comment, you can also use runtime.Gosched() instead of sleep.
Usage of defer incorrect, defer execute at end of function, not for statement.
func StoreUrl(id int, url string) {
for {
func() {
lock.Lock()
defer lock.Unlock()
m[id] = url
}()
}
}
or
func StoreUrl(id int, url string) {
for {
lock.Lock()
m[id] = url
lock.Unlock()
}
}
We can't control the order of go routine, so add time.Sleep() to control the order.
code here:
https://play.golang.org/p/Bu8Lo46SA2

do repetitive tasks at intervals in golang using time.AfterFunc, just a sample

I just want to do repetitive background tasks in Go, using time.AfterFunc,But seems something wrong with the logic.
The out put just:
interval call
interval call
But at least 5 times to call the function if all things went normal.
package main
import (
"fmt"
"time"
"os"
"os/signal"
)
type Timer struct {
Queue chan *TimeCall
}
func NewTimer(l int) *Timer {
timer := new(Timer)
timer.Queue = make(chan *TimeCall,l)
return timer
}
type TimeCall struct {
timer *time.Timer
callback func()
}
func (this *TimeCall) CallBack() {
defer func() { recover() }()
if this.callback != nil {
this.callback()
}
}
func (this *Timer) AfterFunc(d time.Duration, callback func()) *TimeCall {
call := new(TimeCall)
call.callback = callback
call.timer = time.AfterFunc(d, func() {
this.Queue <- call
})
return call
}
type PipeService struct {
TimeCall *Timer
}
func (this *PipeService) AfterFunc(delay time.Duration, callback func()) *TimeCall {
return this.TimeCall.AfterFunc(delay, callback)
}
func (this *PipeService) IntervalCall(interval time.Duration, callback func()) {
this.TimeCall.AfterFunc(interval,func(){
if callback != nil {
callback()
}
this.AfterFunc(interval,callback)
})
}
func (this *PipeService) Run(closeSig chan bool) {
for {
select {
case <-closeSig:
return
case call := <-this.TimeCall.Queue:
call.CallBack()
}
}
}
func main() {
var closeChan chan bool
InsPipeService := &PipeService{TimeCall: NewTimer(10)}
InsPipeService.IntervalCall(2*time.Second,func(){
fmt.Println("interval call")
})
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
go func(){
InsPipeService.Run(closeChan)
}()
time.Sleep(10*time.Second)
}
Run Code
time.AfterFunc() returns a *time.Timer, quoting form its doc:
The Timer type represents a single event. When the Timer expires, the current time will be sent on C, unless the Timer was created by AfterFunc.
The time.Timer returned by time.AfterFunc() does not repeat, so what you see is perfectly normal: in your PipeService.IntervalCall() you execute the callback immediately, and it gets executed after the timeout.
Also note that you pass 2 as interval for the PipeService.IntervalCall() method. This interval parameter is of type time.Duraion. So when you pass 2, that won't be 2 seconds (but actually 2 nanoseconds). You should pass a value constructed from constants from the time package like:
InsPipeService.IntervalCall(2 * time.Second, func(){
fmt.Println("interval call")
})
If you want repetition, use time.Ticker. For example the following code prints a message in every 2 seconds:
t := time.NewTicker(2 * time.Second)
for now := range t.C {
fmt.Println("tick", now)
}
Or simply if you don't need the Ticker and you don't want to shut it down:
c := time.Tick(2 * time.Second)
for now := range c {
fmt.Println("tick", now)
}
set time interval then call Start it will run user Job on each time intervals. set Enabled to false to stop it.
My Sample:
package main
import (
"fmt"
"sync"
"time"
)
type IntervalTimer struct {
Interval time.Duration
Enabled bool
Job func()
Wg sync.WaitGroup
}
func (it *IntervalTimer) isr() {
if it.Enabled {
it.Job()
time.AfterFunc(it.Interval, it.isr)
} else {
it.Wg.Done()
}
}
//trigger
func (it *IntervalTimer) Start() {
if it.Enabled {
it.Wg.Add(1)
time.AfterFunc(it.Interval, it.isr)
}
}
// user code:
var n int = 5
var it *IntervalTimer
func uerTask() {
fmt.Println(n, time.Now()) // do user job ...
n--
if n == 0 {
it.Enabled = false
}
}
func main() {
it = &IntervalTimer{Interval: 500 * time.Millisecond, Enabled: true, Job: uerTask}
it.Start()
//do some job ...
it.Wg.Wait()
fmt.Println("Bye")
}

CRON JOB in GOLANG

I AM USING IN CRON PKG https://github.com/jasonlvhit/gocron/blob/master/gocron.go
import (
"fmt"
"time"
"github.com/claudiu/gocron"
)
func task() {
fmt.Println("I am runnning task.", time.Now())
}
func vijay() {
fmt.Println("I am runnning vijay.", time.Now())
}
func main() {
go test()
gocron.Start()
s := gocron.NewScheduler()
gocron.Every(5).Seconds().Do(task)
gocron.Every(10).Seconds().Do(vijay)
<-s.Start()
}
func test() {
time.Sleep(20 * time.Second)
gocron.Clear()
fmt.Println("All task removed")
}
My problem is after removing all job, my program is still executing
i want to break the exection after removing all jobs
please help me out ,i am not able to find out how to do it ,
i tried to change the PKG source code also but not able to find out the way to do it
thank you all
First, you're creating a new scheduler, and waiting on it, but using the default scheduler to run your jobs.
Next, you're blocking on the channel returned by the Start() method. Close that channel to unblock the receive operation. This will also exit the main loop in the cron program if you aren't immediately exiting from main.
func main() {
ch := gocron.Start()
go test(ch)
gocron.Every(5).Seconds().Do(task)
gocron.Every(10).Seconds().Do(vijay)
<-ch
}
func test(stop chan bool) {
time.Sleep(20 * time.Second)
gocron.Clear()
fmt.Println("All task removed")
close(stop)
}
which effectively is the same as
func main() {
gocron.Start()
gocron.Every(5).Seconds().Do(task)
gocron.Every(10).Seconds().Do(vijay)
time.Sleep(20 * time.Second)
gocron.Clear()
fmt.Println("All task removed")
}
If you're exiting immediately, it doesn't really matter if you call Clear() first and then stop the scheduler, you can simply exit the program.
JimB rights. But I don't know why do you use gocron methods and the s methods. This example works fine:
package main
import (
"fmt"
"time"
"github.com/claudiu/gocron"
)
func task() {
fmt.Println("I am runnning task.", time.Now())
}
func vijay() {
fmt.Println("I am runnning vijay.", time.Now())
}
func main() {
s := gocron.NewScheduler()
s.Every(2).Seconds().Do(task)
s.Every(4).Seconds().Do(vijay)
sc := s.Start() // keep the channel
go test(s, sc) // wait
<-sc // it will happens if the channel is closed
}
func test(s *gocron.Scheduler, sc chan bool) {
time.Sleep(8 * time.Second)
s.Clear()
fmt.Println("All task removed")
close(sc) // close the channel
}

Resources