Understind how to apply timeout using gouritine

266 views
Skip to first unread message

Juan Mamani

unread,
Feb 24, 2020, 3:55:12 AM2/24/20
to golang-nuts
Hi everybody,

I've tried to adapt from from "Concurrency in Go by Katherine Cox-Buday" to understand how to apply timeout. But I don't get it.  What I'm doing wrong?     Here the code:

package main

import(
  //"fmt"
    "time"
    "math/rand"  
    "log"
)                                                                                                                                                                      

func main(){
  
 // infinity loop                                                                                                                                                                       
  for{
       log.Println("-----------------Start")                                                                                                                                     
      Task()                                                                                                                                                                  
       log.Println("-----------------End")
  }
}
                                                                                                                                                                                                                                                                            // Trying to adapt from Concurrency in Go by Katherine Cox-Buday
func Task(){                                                                                                                                                            
   doWork := func(  done <-chan interface{}, strings <-chan string, ) <-chan interface{} { //1
      terminated := make(chan interface{})                                                                                                                                    
     go func() {                                                                                                                                                                    
               defer log.Println("doWork exited.")                                                                                                                                    
               defer close(terminated)                                                                                                                                                
               for {                                                                                                                                                                       
                 goToSleep()                                                                                                                                                             
                 select {
                      //case s := <-strings:
                      // case s := ran():
                      // Do something interesting                                                                                                                                            
                      //fmt.Println(s)
                      case <-done: //2
                          return
            }
        }
      }()    
  }
                                                                                                                                                                        
  done := make(chan interface{})                                                                                                                                          
  terminated := doWork(done, nil)                                                                                                                                                                                                                                                                                                                 
  go func() { //3                                                                                                                                                          
      // Cancel the operation after 3 second.                                                                                                                                 
     time.Sleep(3 * time.Second)                                                                                                                                             
     log.Println("Canceling doWork goroutine reach 3s...")                                                                                                                  
     close(done)                                                                                                                                                         
  }()                                                                                                                                                                                                                                                                                                                                             
   <-terminated //4                                                                                                                                                       
   log.Println("Done.")                                                                                                                                                    }                                                                                      
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
 func goToSleep(){                                                                                                                                                                                 
     rand.Seed(time.Now().UnixNano())
     n := rand.Intn(10)
     log.Printf("Sleeping %d seconds....\n",n)
     time.Sleep(time.Duration(n)*time.Second)
     log.Println("Done sleeping!")
}                                                                                                              

//-------------------------------------

Thanks
JM


Lutz Horn

unread,
Feb 24, 2020, 4:09:09 AM2/24/20
to golang-nuts
> I've tried to adapt from from "Concurrency in Go by Katherine Cox-Buday" to
> understand how to apply timeout. But I don't get it.

What are you trying to do? What is the expected behaviour, what happens instead?

BTW, this code does not compile, there are same unbalanced curly brackets.

Lutz

Juan Mamani

unread,
Feb 24, 2020, 10:01:01 AM2/24/20
to golang-nuts
Sorry}, here is the right code:  ( just was the effect to b working til At 5:20am  sleepy and lost)

Expected behaviour is  to end  anonyimous func when  3s timeout is reached.

//------------------------------------------------
package main

import(
//"fmt"
"time"
"math/rand"
"log"
)

func main(){

 for{
   log.Println("-----------------Start")
   Task()
   log.Println("-----------------End")

  }

}


// Trying to adapt from Concurrency in Go by Katherine Cox-Buday
func Task(){

doWork := func(  done <-chan interface{}, strings <-chan string, ) <-chan interface{} { //1
    terminated := make(chan interface{})
    go func() {
        defer log.Println("doWork exited.")
        defer close(terminated)
        for {
            goToSleep()
            select {
             //case s := <-strings:
             // case s := ran():
                // Do something interesting
                //fmt.Println(s)
            case <-done: //2
                return
            }
        }
    }()
    return terminated
}

done := make(chan interface{})
terminated := doWork(done, nil)

go func() { //3
    // Cancel the operation after 3 second.
    time.Sleep(3 * time.Second)
    log.Println("Canceling doWork goroutine reach 3s...")
    close(done)
}()

<-terminated //4
log.Println("Done.")
}

done := make(chan interface{})
terminated := doWork(done, nil)

go func() { //3
    // Cancel the operation after 3 second.
    time.Sleep(3 * time.Second)
    log.Println("Canceling doWork goroutine reach 3s...")
    close(done)
}()

<-terminated //4
log.Println("Done.")
}



func goToSleep(){
                                                                                                                                                                                                                                                 
rand.Seed(time.Now().UnixNano())
    n := rand.Intn(12) // n will be between 0 and 10
    log.Println("Sleeping ",n,"seconds..")
    time.Sleep(time.Duration(n)*time.Second)
    log.Println("Done sleeping!")
}

//------------------------------------------------

Jake Montgomery

unread,
Feb 24, 2020, 12:16:32 PM2/24/20
to golang-nuts
Your code will still not compile. In this group, it is often helpful to include a link to your code in the playground (https://play.golang.org/) using the "Share" button. That is in addition to, or instead of, posting your code in the message. This will allow others to easily run your code, but also will allow you to make sure it compiles.

Juan Mamani

unread,
Feb 24, 2020, 6:45:26 PM2/24/20
to golang-nuts
Sorry again.   Well, I followed your advice. Here is the link https://play.golang.org/p/7DigEVsKbdx
How can I cancel goToSleep() when timeout is reached?

Michel Levieux

unread,
Feb 25, 2020, 3:43:00 AM2/25/20
to Juan Mamani, golang-nuts
Hi Juan,

You cannot terminate a function execution from its caller if you did not pass it an argument (most likely a channel) which it can use to communicate with its caller, and terminate itself when the timeout is reached.
The simplest example I can think of is the following: https://play.golang.org/p/KVQ7uhiWr7H, though I'm not quite sure this is your question, since it looks like you've already experimented with this construct.

You can trick with signals and other constructs but channels are designed for that kind of need, so I suppose this is the best way to go. If you want something that wraps this behaviour because you need the timeout to follow the logic of your program, maybe package https://golang.org/pkg/context/ can help you.

Hope this was useful!

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/b0828575-fddf-4024-bec0-8faf5b9858a4%40googlegroups.com.

Michel Levieux

unread,
Feb 25, 2020, 3:45:17 AM2/25/20
to Juan Mamani, golang-nuts
Edit: I said "communicate with its caller" but in practice it might as well be another goroutine or the caller of the caller, either way the construct and the logic standing behind it are exactly the same :)

Jake Montgomery

unread,
Feb 25, 2020, 11:45:03 AM2/25/20
to golang-nuts
Expected behaviour is  to end  anonyimous func when  3s timeout is reached.

So what is the problem? The whole thing does exit after 3 seconds. Of course, your main() is a loop, so it starts again.

2009/11/10 23:00:00 -----------------Start
2009/11/10 23:00:03 Canceling doWork goroutine reach 3s...
2009/11/10 23:00:03 doWork exited.
2009/11/10 23:00:03 Done.
2009/11/10 23:00:03 -----------------End

What exactly did you expect to see other than that?

Juan Mamani

unread,
Feb 25, 2020, 8:03:29 PM2/25/20
to golang-nuts
Reallly thanks for your help and guide!

To unsubscribe from this group and stop receiving emails from it, send an email to golan...@googlegroups.com.

Juan Mamani

unread,
Feb 25, 2020, 8:38:27 PM2/25/20
to golang-nuts
Ok, you are right.  But I was confused with this:

2009/11/10 23:00:00 -----------------Start
2009/11/10 23:00:00 Sleeping  8 seconds..
2009/11/10 23:00:03 Canceling doWork goroutine reach 3s...
2009/11/10 23:00:08 Done sleeping!
2009/11/10 23:00:08 doWork exited.
2009/11/10 23:00:08 Done.
2009/11/10 23:00:08 -----------------End

My previous questions were: How can I cancel execution of goToSleep() function?  How can I break it? Because I expect  code to stop function gotoTosleep()  at 3s, but I saw still running at 8s because prints "Done sleeping!"..
But Michael Levieux got the idea and repliedr:"You cannot terminate a function execution from its caller.." .  So I was wrong in my understanding how to implement "cancel" or "break" goroutinea.

Juan Mamani

unread,
Feb 25, 2020, 9:02:35 PM2/25/20
to golang-nuts
Hi Michel,

I've tried your sample with this result:

2020/02/25 23:12:51.854561 Stop in 2s
2020/02/25 23:12:51.854710 Hey!
2020/02/25 23:12:57.854967 Bye Bye!

But function still running."Bye Bye" appeared  +6s later.   I will check Context package as you recomended me.
Thanks!
To unsubscribe from this group and stop receiving emails from it, send an email to golan...@googlegroups.com.

Jake Montgomery

unread,
Feb 26, 2020, 7:19:53 AM2/26/20
to golang-nuts
The code you posted above never actually called goToSleep(), because the 'strings ' channel was nil. Could you post a playground link to the new code that you are running below?


On Tuesday, February 25, 2020 at 8:38:27 PM UTC-5, Juan Mamani wrote:
Ok, you are right.  But I was confused with this:

2009/11/10 23:00:00 -----------------Start
2009/11/10 23:00:00 Sleeping  8 seconds..
2009/11/10 23:00:03 Canceling doWork goroutine reach 3s...
2009/11/10 23:00:08 Done sleeping!

2009/11/10 23:00:08 doWork exited.
2009/11/10 23:00:08 Done.
2009/11/10 23:00:08 -----------------End

My previous questions were: How can I cancel execution ofv function?  How can I break it? Because I expect  code to stop function gotoTosleep()  at 3s, but I saw still running at 8s because prints "Done sleeping!"..

Brian Candler

unread,
Feb 26, 2020, 8:22:24 AM2/26/20
to golang-nuts
My previous questions were: How can I cancel execution of goToSleep() function?  How can I break it?

Maybe you want something like this?

context is the standard way to be able to cancel one or more of goroutines, such as those working together to handle a particular request.  The goroutines need to cooperate with this mechanism, by noticing that the cancellation signal has been sent and then finishing. This is done inside interruptibleSleep in the above example. Many library functions now accept a context so that they can be terminated in this way.

Also, if the point of this is to give up after a timeout, the context itself can carry a deadline, which simplifies things:

Brian Candler

unread,
Feb 26, 2020, 8:41:26 AM2/26/20
to golang-nuts
Perhaps slightly clearer:
 

Juan Mamani

unread,
Feb 27, 2020, 2:29:24 PM2/27/20
to golang-nuts
Hi Brian,

Thanks for your help.  I will try out  to implement your samples in my project.
But still studying Goroutines and now Context.

Brian Candler

unread,
Feb 27, 2020, 3:52:56 PM2/27/20
to golang-nuts
The magic behind contexts is that they use a channel but without sending any data over it.  Instead, *closing* the channel is a signal to terminate.

This allows you to have multiple goroutines listening on the channel, and they will *all* receive the termination signal, as a broadcast.  (It wouldn't work if you sent an item of data on the channel: if you did that, then only one of the receivers would get it)

Jake Montgomery

unread,
Feb 28, 2020, 11:35:32 AM2/28/20
to golang-nuts
Contexts are great. And if your goal is to solve a specific problem, then sometimes they may be the best solution. But you implied in your OP that you were learning go. And in that case, I would still urge you to understand your original channel based code, and why it does not work, and how to make it work.
Reply all
Reply to author
Forward
0 new messages