We got init() why no final()

2,378 views
Skip to first unread message

RoboTamer

unread,
Sep 30, 2012, 10:58:05 PM9/30/12
to golan...@googlegroups.com

We have init() to initialize function and I need a finalize function also.
I created the code below, but it doesn't work when the code gets terminated with Ctrl-c
I need that to work! Any solutions?

This is for a mail script:


func init() {
    go loop()
}

func loop() {
    defer final()
    for {
        send()
        sleep(2)
    }
}

func final() {
    write()
}







Dan Kortschak

unread,
Sep 30, 2012, 11:01:12 PM9/30/12
to RoboTamer, golan...@googlegroups.com
Intercept the signal an then finish up.
--
 
 

Patrick Mylund Nielsen

unread,
Sep 30, 2012, 11:01:26 PM9/30/12
to RoboTamer, golan...@googlegroups.com
See https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/PCVy2dGGai0

For your problem, you need signal handling:

func signalCatcher() {
ch := make(chan os.Signal)
signal.Notify(ch, syscall.SIGINT)
<-ch
log.Println("CTRL-C; exiting")
os.Exit(0)
}

func main() {
go signalCatcher()
...
> --
>
>

RoboTamer

unread,
Oct 1, 2012, 12:24:53 AM10/1/12
to golan...@googlegroups.com, RoboTamer

On Sunday, September 30, 2012 8:01:32 PM UTC-7, Patrick Mylund Nielsen wrote:
See https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/PCVy2dGGai0

For your problem, you need signal handling:

func signalCatcher() {
        ch := make(chan os.Signal)
        signal.Notify(ch, syscall.SIGINT)
        <-ch
        log.Println("CTRL-C; exiting")
        os.Exit(0)
}

func main() {
        go signalCatcher()
        ...
}


Can't get it to work.
Here is what I got: 

package main
import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

func signalCatcher() {
    ch := make(chan os.Signal)
    signal.Notify(ch, syscall.SIGINT)
    <-ch
    fmt.Println("CTRL-C; exiting")
    os.Exit(0)
}

func main() {
    go signalCatcher() // Does not prints "CTRL-C; exiting"
    // signalCatcher() // prints "CTRL-C; exiting" but doesn't run the code below
    i := 0
    for {
        println(i)
        i++
    }
}

Joseph Poirier

unread,
Oct 1, 2012, 12:39:46 AM10/1/12
to RoboTamer, golan...@googlegroups.com
> --
>
>

It works on OS X 10.7.5 and tip.

si guy

unread,
Oct 1, 2012, 12:43:29 AM10/1/12
to golan...@googlegroups.com
I think your main loop may be too tight, it might not be yielding to the other goroutine. Try throwing a runtime.Gosched() in there, just a hunch since I'm not at a terminal right now.

-Simon Watt

Patrick Mylund Nielsen

unread,
Oct 1, 2012, 12:44:55 AM10/1/12
to RoboTamer, golan...@googlegroups.com
replace the for {} with select {}, run the bin with GOMAXPROCS=2 or
above, or call runtime.Gosched() inside the for loop. It's never
switching away from the for loop because of the cooperative
scheduling.

On Sun, Sep 30, 2012 at 11:24 PM, RoboTamer <grue...@gmail.com> wrote:
>
> --
>
>

Joseph Poirier

unread,
Oct 1, 2012, 12:47:49 AM10/1/12
to Patrick Mylund Nielsen, RoboTamer, golan...@googlegroups.com
Yeah, sorry; I already had runtime.GOMAXPROCS(2) in the test file.
> --
>
>

RoboTamer

unread,
Oct 1, 2012, 7:53:03 AM10/1/12
to golan...@googlegroups.com, Patrick Mylund Nielsen, RoboTamer

It's working now.
Thanks so much guys,
Below is the working code, in case someone else needs it.


package main

import (
    "fmt"
    "os"
    "os/signal"
    "runtime"
    "syscall"
)

func signalCatcher() {
    ch := make(chan os.Signal)
    signal.Notify(ch, syscall.SIGINT)
    <-ch
    fmt.Println("CTRL-C; exiting")
    os.Exit(0)
}

func main() {
    go signalCatcher()
    i := 0
    for {
        runtime.GOMAXPROCS(2) // http://golang.org/pkg/runtime/#GOMAXPROCS
        println(i)
        i++
    }
}

RoboTamer

unread,
Oct 1, 2012, 9:36:12 PM10/1/12
to golan...@googlegroups.com, Patrick Mylund Nielsen, RoboTamer
On Monday, October 1, 2012 12:51:32 PM UTC-7, Jeremy Jackins wrote:
I'm guessing you meant to put your call to runtime.GOMAXPROCS(2) outside of the for loop.



No  didn't know it was supposed to be outside, thanks for that.
I am actually using runtime.Gosched() now.
So here it is:

package main

import (
    "fmt"
    "os"
    "os/signal"
    "runtime"
    "syscall"
    "time"
)

func signalCatcher() {
    ch := make(chan os.Signal)
    signal.Notify(ch, syscall.SIGINT)
    <-ch
    fmt.Println("CTRL-C; exiting")
    os.Exit(0)
}

func main() {
    go signalCatcher()
    i := 0
    runtime.Gosched()
    for {
        println(i)
        i++
        sleep(1)
    }
}
func sleep(sec time.Duration) {
    time.Sleep(time.Second * sec)
}

Dave Cheney

unread,
Oct 1, 2012, 9:45:26 PM10/1/12
to RoboTamer, golan...@googlegroups.com, Patrick Mylund Nielsen
> runtime.Gosched()

^ this does not do what you think it does

> for {
>
> println(i)
>
> i++
>
> sleep(1)

^ this is actually letting the runtime schedule other goroutines.

RoboTamer

unread,
Oct 1, 2012, 11:04:14 PM10/1/12
to golan...@googlegroups.com, RoboTamer, Patrick Mylund Nielsen
For GOMAXPROCS it says:
This call will go away when the scheduler improves.
And Gosched()  works, I don't understand why it does. Is there a reason not to use it?

Patrick Mylund Nielsen

unread,
Oct 1, 2012, 11:12:41 PM10/1/12
to RoboTamer, golan...@googlegroups.com
runtime.GOMAXPROCS means "set GOMAXPROCS for the lifetime of this process"
runtime.Gosched means "give control to some other goroutine than me right now"

You could replace your sleep call with Gosched in the for loop, and it
would work, but with your current one it is redundant. It's only
necessary to call GOMAXPROCS once, in e.g. init or main. (A common
pattern is to do runtime.GOMAXPROCS(runtime.NumCPU()) if you know that
your application does most things in parallel.)

You should almost never need to run Gosched. The only reason you're
having this problem is that you have a goroutine which never returns
or waits for anything (e.g. a channel.) If you avoid these infinite
loops (e.g. "for {}"), you won't have this problem.

Patrick Mylund Nielsen

unread,
Oct 1, 2012, 11:13:15 PM10/1/12
to RoboTamer, golan...@googlegroups.com
Here's why you shouldn't always use GOMAXPROCS > 1:
http://golang.org/doc/go_faq.html#Why_GOMAXPROCS

RoboTamer

unread,
Oct 1, 2012, 11:34:27 PM10/1/12
to golan...@googlegroups.com, RoboTamer

Thanks for coming down to my level, and the great explanation. Now it all makes sense.
I do need the infinite loop, and i tried increasing the sleep but that didn't work.
I don't won't GOMAXPROCS(2) to be a global thing that is not even an option. I don't wont to be manipulation the app devs work from my little lib.
The only other solution I have is asking the developer to place a defer Final() in to the main() function of his/her application,  which is what I am doing right now anyway.
I guess I should stick with the defer until the Go Team improves the scheduler, and neither use GOMAXPROCS(2) or Gosched() then?  
Or is there another option I don't know about?

Patrick Mylund Nielsen

unread,
Oct 1, 2012, 11:37:28 PM10/1/12
to RoboTamer, golan...@googlegroups.com
I can't believe that you really need a for loop that doesn't do
anything which yields. But yes, if you do, you'll want to do
runtime.Gosched() every once in a while.
> --
>
>

RoboTamer

unread,
Oct 1, 2012, 11:53:02 PM10/1/12
to golan...@googlegroups.com, RoboTamer
The actual package sends email via smtp that is what the for loop is for.
I use a map for mail queuing
Here is a link if you like to check it out

You sad once in awhile that makes sense, so I should place the  Gosched() in to the for loop but execute it only every other time or something like that. Yes of course why would you have every process yield.

Kyle Lemons

unread,
Oct 2, 2012, 3:59:42 AM10/2/12
to RoboTamer, golan...@googlegroups.com
On Sun, Sep 30, 2012 at 7:58 PM, RoboTamer <grue...@gmail.com> wrote:
We have init() to initialize function and I need a finalize function also.
This is a common misconception.  It turns out that it's almost impossible to have a "cleanup" function which is always run as the program is executing.  What if, for instance, the system is in an OOM situation and the kernel is killing off processes so as to not starve itself?  It is often better to clean up as the application is starting up than to attempt to find a way to ensure cleanup is performed as the application is shutting down.  (Not that you shouldn't *try* to clean up when you are exiting cleanly, of course.)
 
I created the code below, but it doesn't work when the code gets terminated with Ctrl-c
I need that to work! Any solutions?

This is for a mail script:


func init() {
    go loop()
}

func loop() {
    defer final()
    for {
        send()
        sleep(2)
    }
}


func final() {
    write()
}







--
 
 

Reply all
Reply to author
Forward
0 new messages