how golang starts a task independent of the main task

69 Views Asked by At

How golang starts a task, the main task returns, but the asynchronous task can continue to run. It is best to control the timeout of the task, such as through ctx control.

my code is

package main

import (
    "fmt"
    "time"
)

func asyncTask() {
    fmt.Println("task start")
    time.Sleep(2 * time.Second)
    fmt.Println("task end")
}

func main() {
    fmt.Println("main start ")

    go asyncTask()

    fmt.Println("task...")
    time.Sleep(3 * time.Second)
    fmt.Println("main end")
}

i hope the main function does not need to sleep. The task continues to run after returning.

3

There are 3 best solutions below

0
Schwern On

When main exits, the program ends and all goroutines shut down. main must have a way to wait until all goroutines end. You're correct that there are better ways than sleeping; sleeping in concurrent code is a red flag. Here are some basic options.

Simplest is to use a channel.

package main

import (
    "fmt"
    "time"
)

func worker(done chan bool) {
    fmt.Print("working...")
    time.Sleep(time.Second)
    fmt.Println("done") 

    done <- true
}

func main() {
    done := make(chan bool, 1)
    go worker(done) 

    <-done
}

main makes a channel and passes it into the worker. <-done causes main to wait until there's something to read. Once worker is done, it sends a true value down the done channel (the value doesn't matter), main reads it and can continue.

For more workers use WaitGroups.

package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup   

    for i := 1; i <= 5; i++ {
        wg.Add(1)

        go func() {
            defer wg.Done()
            worker(i)
        }()
    }   

    wg.Wait()
}

main creates a sync.WaitGroup. Each time it starts a goroutine it adds 1 to the group. Each worker is wrapped in a goroutine which will call wg.Done when the work is done subtracting 1 from the group. wg.Wait() will wait until the WaitGroup is back to 0 indicating all workers are done.

0
juanmonroynieto On

The go runtime manages all goroutines. Your question seems to intend to ask how to guarantee the execution of the code in a go routine even when the main has finished its work. The answer to this is waitgroups and the sync package.

Your toy example could have a larger wait time in the go routine to test what would happen.

package main

import (
    "fmt"
    "sync"
    "time"
)

func asyncTask(sleepTime int, wg *sync.WaitGroup) {
    fmt.Printf("task start %ds\n", sleepTime)
    time.Sleep(time.Duration(sleepTime) * time.Second)
    fmt.Printf("task end :%ds\n", sleepTime)
    if wg != nil {
        defer wg.Done()
    }
}

func main() {
    fmt.Println("->main start ")
    var wg sync.WaitGroup
    wg.Add(1)
    go asyncTask(6, nil)
    go asyncTask(4, &wg)
    time.Sleep(2 * time.Second)
    fmt.Println("->main end")
    wg.Wait()
}

The first one does not reach the end, while the second one does (even sleeping for a second longer).

I recommend you read the GoByExample simple example, the sync documentation, this fantastic answer on the sync package use with pointers.

0
Abdul Aleem On

You need not to put sleep in main thread, the thing is in golang main thread is the last thread which exit the program,

By default there will be a main thread so condition is that all the other thread which is being initiated by main thread must complete themselves.

For doing the other complete we can use multiple things

  • Channel

    Channal are the conduit between two thread to communicate.

  • WaitGroup

    Waitgroup are generally used when one or more thread or worker are doing some task, asynchronously, waitgroup contains stats of the other thread are they done or not.