在将上下文传递给Go协程时使用context.WithDeadline函数可以设置截止时间。

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

context.WithDeadline while passing context to go routine?

问题

在将上下文传递给Go协程时使用context.WithDeadline吗?

我编写了一些示例代码,将为切片中的每个项启动一个新的goroutine。
目前,这将等待done通道被调用len(slice)次。

然而,我还想在goroutine中实现超时以防止事件泄漏。
似乎context.WithDeadline(或者可能是WithTimeout?)是适合使用的函数。

例如,假设我想为从main()初始化的所有goroutine传递一个23秒的截止时间。
然而,我不清楚应该如何做到这一点。

我阅读了godoc以及Go并发模式:上下文(在Go博客上),但作为一个新手,我一无所知。
我找到的许多示例使用http.handler(或类似的示例),所以它们让我感到困惑。

在这里传递带有截止时间/超时的上下文的适当方法是什么?

package main

import (
  "fmt"
  "time"
)

func sleepNow(i int, done chan bool) {
  time.Sleep(time.Duration(i) * time.Second)
  fmt.Println(i, "刚刚从睡眠中醒来,现在的时间是", time.Now())
  
  done <- true
}

func main() {
  done := make(chan bool)
  numbersSlice := []int{10, 20, 30, 12}
  
  for _, v := range(numbersSlice){
    go sleepNow(v, done)
  }
  
  for x := 0; x < len(numbersSlice); x++ {
    <-done
  }
  fmt.Println("看起来我们都完成了!")
  
}
英文:

context.WithDeadline while passing context to go routine?

I have put together some sample code that will start a new goroutine for every item in my slice.
At the moment, this will wait for the done channel to be called len(slice) times.

However, I would also like to implement a timeout in the goroutines to event leaking.
It seems that context.WithDeadline (or maybe WithTimeout?)is the appropriate function to use.

For example, lets say I want to pass in a 23 second deadline for all goroutines that are initialized from main().
However, its not clear to me how I should do this.

I have read godoc along with Go Concurrency Patterns: Context (on the go blog) but as a new gopher,
I am none the wiser. Many of the examples that I have found use http.handler(or similar as examples and so they are a source of some confusion for me.

What is an appropriate way to pass in context with deadline / timeout here.

package main

import (
  &quot;fmt&quot;
  &quot;time&quot;
)

func sleepNow(i int, done chan bool) {
  time.Sleep(time.Duration(i) * time.Second)
  fmt.Println(i, &quot;has just woken up from sleep and the time is&quot;, time.Now())
  
  done &lt;- true
}

func main() {
  done := make(chan bool)
  numbersSlice := []int{10, 20, 30, 12}
  
  for _, v := range(numbersSlice){
    go sleepNow(v, done)
  }
  
  for x := 0; x &lt; len(numbersSlice); x++ {
  &lt;-done
  }
  fmt.Println(&quot;Looks like we are all done here!&quot;)
  
}

答案1

得分: 3

你只需要将上下文传递到想要使用它的函数中即可。在许多情况下,你可以使用一个简单的闭包,或者在这种情况下,将其添加到函数参数中。

一旦你将上下文放置好,你可以选择在Context.Done()通道上进行选择,以确定何时过期。

func sleepNow(i int, ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()

    select {
    case <-time.After(time.Duration(i) * time.Second):
        fmt.Println(i, "刚刚从睡眠中醒来,现在的时间是", time.Now())
    case <-ctx.Done():
        fmt.Println(i, "刚刚被取消")
    }
}

func main() {
    var wg sync.WaitGroup
    numbersSlice := []int{1, 5, 4, 2}

    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)

    for _, v := range numbersSlice {
        wg.Add(1)
        go sleepNow(v, ctx, &wg)
    }

    wg.Wait()
    cancel()

    fmt.Println("看起来我们已经完成了!")
}

你还应该使用sync.WaitGroup而不是依赖于通过通道计数的方法,并使用defer来调用Done

英文:

All you need to do is get the context into the function where you want to use it. In many cases you can use a simple closure, or in this case, add it to the function arguments.

Once you have the context in place, you can select on the Context.Done() channel to determine when it has expired.

https://play.golang.org/p/q-n_2mIW2X

func sleepNow(i int, ctx context.Context, wg *sync.WaitGroup) {
	defer wg.Done()

	select {
	case &lt;-time.After(time.Duration(i) * time.Second):
		fmt.Println(i, &quot;has just woken up from sleep and the time is&quot;, time.Now())
	case &lt;-ctx.Done():
		fmt.Println(i, &quot;has just been canceled&quot;)
	}
}

func main() {
	var wg sync.WaitGroup
	numbersSlice := []int{1, 5, 4, 2}

	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)

	for _, v := range numbersSlice {
		wg.Add(1)
		go sleepNow(v, ctx, &amp;wg)
	}

	wg.Wait()
	cancel()

	fmt.Println(&quot;Looks like we are all done here!&quot;)
}

You should also use a sync.WaitGroup rather than rely on counting tokens over channel, and use defer to call Done.

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

发表评论

匿名网友

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

确定