How to cancel goroutines after certain amount of time

huangapple go评论71阅读模式
英文:

How to cancel goroutines after certain amount of time

问题

我正在制作一个负载测试工具,它在goroutine中进行多个HTTP调用,目前它可以正常工作,但现在我想让它只运行指定的持续时间。

当sleep完成后,我该如何取消goroutine?

我目前尝试的方法是创建一个goroutine,在指定的持续时间内执行time.Sleep(),当时间到达后,它会向通道发送一条消息。

在我的无限循环中,我使用switch语句监听该消息,当消息到达时,我返回。这正是我想要的效果。

问题是,来自go httpPost()行的goroutine将继续进行HTTP调用。我甚至尝试将通道传递给该函数,并在那里监听相同的CALL_TIME_RAN_OUT消息,但由于某种原因,当我这样做时,goroutine只运行一次,然后立即返回,而不是等待Sleep结束时广播的消息。

有人知道我可以采取更好的方法吗?这种方法似乎不起作用。

以下是代码(已删除不相关的部分):

func attack(cfg AttackConfig) {
    // 一些代码...

    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 {
        // 其他一些case...
        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) {
    // 一些创建HTTP客户端的代码...

    for {
        // 一些进行HTTP调用的代码...

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

希望对你有所帮助!

英文:

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 &lt;- CALL_TIME_RAN_OUT
	}()

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

		switch &lt;-ch {
		// some other cases ...
		case CALL_TIME_RAN_OUT:
			fmt.Printf(&quot;%d seconds have elapsed. Shutting down!&quot;, 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 &lt;-ch {
		case CALL_TIME_RAN_OUT:
			return
		}
	}
}

答案1

得分: 2

使用golang.org/x/net/context包。Go 1.7将golang.org/x/net/context包移入标准库,命名为context
所以如果你使用1.7+版本,只需导入context

使用方法很简单:

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)
}
英文:

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 (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;time&quot;
)

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

	select {
	case &lt;-time.After(1 * time.Second):
		fmt.Println(&quot;overslept&quot;)
	case &lt;-ctx.Done():
	}
	fmt.Println(&quot;used:&quot;, time.Since(t))
}

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

huangapple
  • 本文由 发表于 2017年3月27日 06:26:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/43035331.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定