在golang中使用context包需要进一步澄清。

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

Clarification required on use of context package in golang

问题

我正在学习Go语言。
我了解取消上下文可以在父操作或相关操作取消后中止操作。这样可以节省正在进行的操作的资源,因为它们的结果将不会被使用。现在考虑下面的简单代码:

 package main
 
 import (
 	"context"
 	"fmt"
 	"time"
 )
 
 func main() {
 	var result int
 	ctx := context.Background()
 	ctx, cancel := context.WithCancel(ctx)
 	ch1 := make(chan int)
 
 	go func() {
 		time.Sleep(time.Second * 5)
 		//...进行一些处理
 		//在通道上发送结果或在出现错误时取消
        //让我们发送结果...
 		ch1 <- 11
 	}()
 
 	go func() {
 		time.Sleep(time.Second * 2)
 		//...进行一些处理
 		//在通道上发送结果或在出现错误时取消
        //让我们取消...
 		cancel()
 	}()
 
 	select {
 	case result = <-ch1:
 		fmt.Println("处理完成", result)
 	case <-ctx.Done():
 		fmt.Println("ctx已取消")
 	}
 
 	//其他一些处理...  
 
 }

select语句通过ctx.Done()满足条件。我有一个问题,即使调用了cancel,第一个goroutine也会继续执行,因为程序会继续执行"其他一些处理..."。
因此,使用上下文的基本目的没有实现。我认为我在理解上有些问题,或者是否有一种方法可以在上下文取消后中止结果将不会被使用的goroutine。
请澄清一下。

英文:

I am learning the Go language.
I understand that cancelling a context enables aborting of operations once the parent or related operation is cancelled. This is supposed to save resources of ongoing operations whose results will not be used. Now consider the simple code below:

 package main
 
 import (
 	&quot;context&quot;
 	&quot;fmt&quot;
 	&quot;time&quot;
 )
 
 func main() {
 	var result int
 	ctx := context.Background()
 	ctx, cancel := context.WithCancel(ctx)
 	ch1 := make(chan int)
 
 	go func() {
 		time.Sleep(time.Second * 5)
 		//...do some processing
 		//Send result on the channel or cancel if error
        //Lets send result...
 		ch1 &lt;- 11
 	}()
 
 	go func() {
 		time.Sleep(time.Second * 2)
 		//...do some processing
 		//Send result on the channel or cancel if error
        //Lets cancel...
 		cancel()
 	}()
 
 	select {
 	case result = &lt;-ch1:
 		fmt.Println(&quot;Processing completed&quot;, result)
 	case &lt;-ctx.Done():
 		fmt.Println(&quot;ctx Cancelled&quot;)
 	}
 
 	//Some other processing...  
 
 }

The select statement is satisfied by the ctx.Done(). The question that I have is that even after the cancel is invoked, the first goroutine will continue as the program proceeds with "Some other processing..."
Therefore, the basic purpose of using context is not served. I think that I am missing something in my understanding or is there a way to abort the goroutine whose result will not be of any use after the context is cancelled.
Please clarify.

答案1

得分: 1

重点是你应该通知第一个 goroutine 发生了某事,并且它需要退出当前的例程。这就是 select 在 golang 中作为 io 多路复用提供的功能。第一个 goroutine 应该像这样:

go func() {
    select {
    case <-time.After(time.Second * 5):
        //...进行一些处理
        //在通道上发送结果或者在出现错误时取消
        //让我们发送结果...
        ch1 <- 11
    case <-ctx.Done():
        fmt.Println("ctx 取消了。")
        return
    }
}()
英文:

The point is you should notify the first goroutine that sth happened, and it need to exit the current routine. That is what select doing as an io-multiplexing provided by golang. The first goroutine should look like this

 go func() {
		select {
		case &lt;-time.After(time.Second * 5):
			//...do some processing
			//Send result on the channel or cancel if error
			//Lets send result...
			ch1 &lt;- 11
		case &lt;-ctx.Done():
			fmt.Println(&quot;ctx Cancelled again.&quot;)
			return
		}
	}()

huangapple
  • 本文由 发表于 2022年2月9日 12:31:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/71044026.html
匿名

发表评论

匿名网友

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

确定