为了账号安全,请及时绑定邮箱和手机立即绑定

我怎样才能避免死锁

我怎样才能避免死锁

Go
拉风的咖菲猫 2021-09-13 10:07:43
看下面的代码片段。package mainimport (    "errors"    "fmt"    "math/rand"    "runtime"    "sync"    "time")func random(min, max int) int {    rand.Seed(time.Now().Unix())    return rand.Intn(max-min) + min}func err1(rand int, chErr chan error, wg *sync.WaitGroup) {    if rand == 1 {        chErr <- errors.New("Error 1")    }    wg.Done()}func err2(rand int, chErr chan error, wg *sync.WaitGroup) {    if rand == 2 {        chErr <- errors.New("Error 2")    }    wg.Done()}func err3(rand int, chErr chan error, wg *sync.WaitGroup) {    if rand == 3 {        chErr <- errors.New("Error 3")    }    wg.Done()}func err4(rand int, chErr chan error, wg *sync.WaitGroup) {    if rand == 3 {        chErr <- errors.New("Error 4")    }    wg.Done()}func err5(rand int, chErr chan error, wg *sync.WaitGroup) {    if rand == 4 {        chErr <- errors.New("Error 5")    }    wg.Done()}func main() {    runtime.GOMAXPROCS(runtime.NumCPU())    chErr := make(chan error, 1)    wg := new(sync.WaitGroup)    //n := random(1, 8)    n := 3    fmt.Println(n)    wg.Add(5)    go err1(n, chErr, wg)    go err2(n, chErr, wg)    go err3(n, chErr, wg)    go err4(n, chErr, wg)    go err5(n, chErr, wg)    fmt.Println("Wait")    wg.Wait()    select {    case err := <-chErr:        fmt.Println(err)        close(chErr)    default:        fmt.Println("NO error, job done")    }}我怎样才能避免这里的僵局?我可以指定缓冲区长度为 2,但也许它有更优雅的方法来解决问题。我有意识地在函数 err3 和 err4 上做了 rand == 3 。
查看完整描述

3 回答

?
catspeake

TA贡献1111条经验 获得超0个赞

通常,不要陷入认为更大的缓冲区可以修复死锁的陷阱。这种方法可能在某些特定情况下有效,但通常并非如此。

死锁最好通过了解 goroutine 如何相互依赖来解决。本质上,您必须消除相互依赖的通信循环。非阻塞发送的想法(参见@izca 的回答)是一种有用的技巧,但不是唯一的技巧。

有大量关于如何避免死锁/活锁的知识。其中大部分来自奥卡姆在 80 年代和 90 年代流行的日子。有一些来自诸如 Jeremy Martin(无死锁并发系统的设计策略)、Peter Welch(高级范式)等人的特别珍宝。

  1. 客户端-服务器策略很简单:将您的 Go 例程网络描述为一组通信服务器及其客户端;确保网络图中没有循环 => 消除了死锁。

  2. I/o-par 是一种形成 Go-routines 的环和环的方法,这样结构内就不会出现死锁;这就是循环特定情况下允许的,但行为方式一般无死锁的方式。

所以,我的策略是首先减少缓冲区大小,考虑发生了什么,修复死锁。然后,根据基准重新引入缓冲区以提高性能。死锁是由通信图中的循环引起的。打破循环。


查看完整回答
反对 回复 2021-09-13
?
犯罪嫌疑人X

TA贡献2080条经验 获得超4个赞

您的节目陷入僵局,因为您的频道已满。

您的频道大小为 1。然后调用wg.Wait().. 等待调用5 个函数。现在,一旦您到达err3.. rand == 3,因此您的频道会传递错误。

此时,您的频道已满,您只勾选了 3 个等待组项目。

err4使用值 3 .. 调用它也想在您的频道上放置错误。此时,它会阻止 - 因为您的频道已满并且没有从中弹出任何内容。

所以你的主要 goroutine 会阻塞,因为你的等待组永远不会完成。

修复确实是使您的通道缓冲区更大。这样,当错误试图放置在通道上时 - 它不会阻塞,并且您的等待组有机会勾选它的所有项目。


查看完整回答
反对 回复 2021-09-13
  • 3 回答
  • 0 关注
  • 175 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信