Strange in Go start groutine in loop with cancel context

Viewed 30

my situation: processor have three retry, and spend second peer retry, and processor cannot be timeout, so i use the CancelContext to controll it.

my processor function:

func process(ctx context.Context, ch chan<- int) {
    fmt.Println("process execute")
    select {
    case <-ctx.Done():
        fmt.Println("process receive done signal, return")
        return
    default:
        fmt.Println("execute default")
        time.Sleep(4 * time.Second) // something handle...
        ch <- 1
        return
    }
}

situation 1

func main(){
    ctx, cancel := context.WithCancel(context.Background()) // handle timeout

    for i := 0; i < 3; i++ { // retry 3
        flag := make(chan int, 1)
        go process(ctx, flag)
        select {
        case <-flag:
            fmt.Println("main receive task done")
        case <-time.After(time.Second * 3):
            cancel()
            fmt.Println("main receive timeout ")
        }
    }
}

output:

process execute
execute default
main receive timeout 
process execute
process receive done signal, return
main receive timeout 
process execute
process receive done signal, return
main receive timeout

question: somethine strange happend, why execute default only print in first loop?

situation 2 i define context in loop:

func main(){
    for i := 0; i < 3; i++ {
        ctx, cancel := context.WithCancel(context.Background()) // define in loop

        flag := make(chan int, 1)
        go process(ctx, flag)
        select {
        case <-flag:
            fmt.Println("main receive task done")
        case <-time.After(time.Second * 3):
            cancel()
            fmt.Println("main receive timeout ")
        }
    }
}

output:

process execute
execute default
main receive timeout 
process execute
execute default
main receive timeout 
process execute
execute default
main receive timeout 

question: why process function never print process receive done signal, return, does it not receive the ctx.Done() singal ?

sorry for my bad english, thank you very much

1 Answers

somethine strange happend, why execute default only print in first loop?

Because when you reach the second and the third process your shared context is already canceled.

why process function never print process receive done signal, return, does it not receive the ctx.Done() singal ?

Because when you call process you execute select and since your context is not done - select goes to the default case and doesn't come back.

Related