英文:
context ctx.Done not being executed even though context was passed to the function in golang
问题
我只会翻译你提供的文本,以下是翻译的结果:
我只是不明白为什么即使我传递了上下文并从主函数调用了取消函数,ctx.Done() 仍然没有被执行。我在这里做错了什么?
var c = make(chan string)
func A(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("killing AAAA")
return // 至少杀死 A
default:
fmt.Println("in A1.. .. again")
c <- "yesss"
}
}
}
//func B(ctx context.Context) {
func main() {
ctx, cancel := context.WithCancel(context.Background())
fmt.Println("BEFORE Number of active goroutines ", runtime.NumGoroutine())
go A(ctx)
time.Sleep(2 * time.Second)
valueReceived := <-c
cancel()
fmt.Println("AFTER Number of active goroutines ", runtime.NumGoroutine())
}
我希望这可以帮助到你。
英文:
I just don't understand why ctx.Done() is not being executed even though I am passing context and calling the cancel from the main? What am I doing wrong here?
var c = make(chan string)
func A(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("killing AAAA")
return // kill A at least
default:
fmt.Println("in A1.. .. again")
c <- "yesss"
}
}
}
//func B(ctx context.Context) {
func main() {
ctx, cancel := context.WithCancel(context.Background())
fmt.Println("BEFORE Number of active goroutines ", runtime.NumGoroutine())
go A(ctx)
time.Sleep(2 * time.Second)
valueReceived := <-c
cancel()
fmt.Println("AFTER Number of active goroutines ", runtime.NumGoroutine())
}
答案1
得分: 4
goroutine执行了默认分支两次,并在发送到c
时阻塞。<-ctx.Done()
分支没有执行,因为goroutine被卡在了默认分支中。
通过从select语句中发送消息而不是分支语句中发送消息来修复这个问题。
func A(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("killing AAAA")
return // 至少杀死A
case c <- "yesss":
fmt.Println("in A1.. .. again")
}
}
}
仅通过这个改变可能看不到killing AAAA
的输出,因为程序可能在goroutine执行完之前就退出了。
等待goroutine执行完毕以查看消息:
var wg sync.WaitGroup
func A(ctx context.Context) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("killing AAAA")
return // 至少杀死A
case c <- "yesss":
fmt.Println("in A1.. .. again")
}
}
}
...
wg.Add(1)
go A(ctx)
time.Sleep(2 * time.Second)
valueReceived := <-c
cancel()
wg.Wait()
英文:
The goroutine executes the default branch twice and blocks on send to c
. The <-ctx.Done()
case is not executed because the goroutine is stuck in the default branch.
Fix the problem by sending from the select case instead of the branch statements.
func A(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("killing AAAA")
return // kill A at least
case c <- "yesss":
fmt.Println("in A1.. .. again")
}
}
}
You may not see the the killing AAAA
with this change alone because the program can exit before the goroutine runs to completion.
Wait for the goroutine to complete to see the message:
var wg sync.WaitGroup
func A(ctx context.Context) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Println("killing AAAA")
return // kill A at least
case c <- "yesss":
fmt.Println("in A1.. .. again")
}
}
}
...
wg.Add(1)
go A(ctx)
time.Sleep(2 * time.Second)
valueReceived := <-c
cancel()
wg.Wait()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论