一定时间后如何取消goroutine

I am making a load testing tool that makes multiple HTTP calls in goroutines, and it works, but now I am trying to allow it to run for only a specified duration.

How can I cancel the goroutines when the sleep has finished?

What I am currently attempting to do is to make a goroutine that does time.Sleep() for the specified duration, and when that is finished it will broadcast a message to the channel.

In my infinite loop, I listen for the message in the switch statement, and when it is there I return. This works just as I want it to.

The problem is, the goroutines from the go httpPost() line will continue making HTTP calls. I even attempt to pass the channel into that function and listen for the same CALL_TIME_RAN_OUT message there as well, but for whatever reason when I do that the goroutines only run once and then immediately return, as opposed to waiting for the message to be broadcasted by the end of the Sleep.

Does anyone know a better approach I can take? This doesn't seem to be working.

Here's the code (removed irrelevant parts):

func attack(cfg AttackConfig) {
    // some code ...

    var ar attackResponse
    ch := make(chan uint8, 8)

    go func() {
        time.Sleep(cfg.Duration * time.Second)
        ch <- CALL_TIME_RAN_OUT
    }()

    for {
        if atomic.LoadInt32(&currConnections) < atomic.LoadInt32(&maxConnections) - 1 {
            go httpPost(cfg, &ar, ch)
        }

        switch <-ch {
        // some other cases ...
        case CALL_TIME_RAN_OUT:
            fmt.Printf("%d seconds have elapsed. Shutting down!", cfg.Duration)
            return
        }
    }
}

func httpPost(cfg AttackConfig, a *attackResponse, ch chan uint8) {
    // some code here to create HTTP client ...

    for {
        // some code to make HTTP call ...

        switch <-ch {
        case CALL_TIME_RAN_OUT:
            return
        }
    }
}

use package golang.org/x/net/context. Go 1.7 moves the golang.org/x/net/context package into the standard library as context. So just import context if you use version 1.7+.

the usage is straightforward:

package main

import (
    "context"
    "fmt"
    "time"
)

func test(ctx context.Context) {
    t := time.Now()

    select {
    case <-time.After(1 * time.Second):
        fmt.Println("overslept")
    case <-ctx.Done():
    }
    fmt.Println("used:", time.Since(t))
}

func main() {
    ctx, _ := context.WithTimeout(context.Background(), 50*time.Millisecond)
    test(ctx)
}