【问题标题】:Go routines and DeferGo 例程和 Defer
【发布时间】:2018-08-03 21:46:52
【问题描述】:
func main() {
    defer fmt.Println("Main defer")
    go t1()
    go t2()
    go t3()
    time.Sleep(20 * time.Second)

}

func t1() {
    defer fmt.Println("t1 defer")
    time.Sleep(20 * time.Second)
}
func t2() {
    defer fmt.Println("t2 defer")
    time.Sleep(5 * time.Second)
    panic(New("T2"))
}
func t3() {
    defer fmt.Println("t3 defer")
    time.Sleep(20 * time.Second)
}

1 个线程 (t2) 调用 panic,t2 defer 被调用。 当 t2 出现紧急情况时,其他所有线程也会终止。 我希望调用每个线程的延迟。 这是一个必须恐慌的场景,恐慌在一个线程中。所以我希望每个线程都知道程序将要退出。 有什么方法可以实现吗?

当前输出:

t2 defer
panic: T2

goroutine 19 [running]:
main.t2()
        C:/Users/Talha.Irfan/OneDrive - Bentley Systems, Inc/Desktop/go_test/src/main2/main.go:34 +0x105
created by main.main
        C:/Users/Talha.Irfan/OneDrive - Bentley Systems, Inc/Desktop/go_test/src/main2/main.go:21 +0xb0

【问题讨论】:

  • panic 调用你的main 程序就像os.Exist 一样存在。所以你可以去log.Println()。在帖子中描述您想要实现的目标
  • 已经描述过了...现在只调用了 1 个 defer...但是总共有 3 个线程..所以我希望每个线程的每个 defer 都被调用
  • 这是一个必须恐慌的场景,恐慌在线程中......所以我希望每个线程都知道程序将要退出。
  • 好的,您可以通过编辑您想要实现的目标和原因在您的帖子中提及它。使用退出通道将值发送到不同的线程
  • 好的,谢谢,我会调查一下

标签: go channel goroutine


【解决方案1】:

代码恐慌后不会调用任何内容。这就是恐慌的工作原理,您的程序将在恐慌之后存在。如果发生恐慌,您可以使用通道将值发送到其他 go 例程。还有一件事,最好使用Wait Groups 等待所有goroutine 完成而不是使用time.Sleep

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    defer fmt.Println("Main defer")
    ch := make(chan int)
    wg.Add(1)
    go t1(ch, &wg)
    wg.Add(1)
    go t2(ch, &wg)
    wg.Add(1)
    go t3(ch, &wg)
    ch <- 1
    close(ch)
    wg.Wait()
}

func t1(ch chan int, wg *sync.WaitGroup) {
    defer fmt.Println("t1 defer")
    defer wg.Done()
}

func t2(ch chan int,wg *sync.WaitGroup) {
    defer fmt.Println("t2 defer")
    for {
         foo, ok := <- ch
         if !ok {
                println("done")
                wg.Done()
                return
         }
         println(foo)
    }
}
func t3(ch chan int, wg *sync.WaitGroup) {
    defer fmt.Println("t3 defer")
    defer wg.Done()
}

Playground Example

如果您在代码中遇到错误,您可以使用恢复来捕获错误。这将导致您的代码运行所有 goroutine。

package main

import (
    "fmt"
    "time"
)

func main() {
    defer fmt.Println("Main defer")
    go t1()
    go t2()
    go t3()
    time.Sleep(2 * time.Second)

}

func t1() {
    defer fmt.Println("t1 defer")
}
func t2() {
    defer fmt.Println("t2 defer")
        defer func() {
            if r := recover(); r != nil {
                println("panic:" + r.(string))
            }
        }()
}
func t3() {
    defer fmt.Println("t3 defer")
}

Go playground 上的工作代码

【讨论】:

  • 好的,你能举个简单的例子来说明通过渠道传递值吗?
  • @TalhaIrfan 检查编辑后的答案以使用通道发送值。
猜你喜欢
  • 2013-11-24
  • 1970-01-01
  • 1970-01-01
  • 2021-10-10
  • 2018-06-08
  • 2020-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多