与通道和 goroutine 同步

Posted

技术标签:

【中文标题】与通道和 goroutine 同步【英文标题】:Sync with channels and goroutines 【发布时间】:2013-05-21 17:34:26 【问题描述】:

我正在尝试实施“工人”系统,但在确定它为什么会自行死锁时遇到了一些问题

代码通过调用fillQueue()来执行

我不明白为什么我的代码最终处于解除锁定状态(一个进程在“process()”的第二行等待,从通道“queue”读取,而另一个在“fillQueue”的末尾等待()" 等待从服务员那里读取。

我不明白为什么它从来没有得到服务员的阅读。

func process(queue chan *entry, waiters chan bool) 
        for 
                entry, ok := <-queue
                if ok == false 
                        break
                
                fmt.Println("worker: " + entry.name)
                entry.name = "whatever"
        
        fmt.Println("worker finished")
        waiters <- true


func fillQueue(q *myQueue) 
        // fill our queue                                                                                                                                                                       
        queue := make(chan *entry, len(q.pool))
        for _, entry := range q.pool 
                fmt.Println("push entry")
                queue <- entry
        
        fmt.Printf("entry cap: %d\n", cap(queue))
        // start the readers                                                                                                                                                                    
        var total_threads int
        if q.maxConcurrent <= len(q.pool) 
                total_threads = q.maxConcurrent
         else 
                total_threads = len(q.pool)
        
        waiters := make(chan bool, total_threads)
        fmt.Printf("waiters cap: %d\n", cap(waiters))
        var threads int
        for threads = 0; threads < total_threads; threads++ 
                fmt.Println("start worker")
                go process(queue, waiters)
        
        fmt.Printf("threads started: %d\n", threads)
        for ; threads > 0; threads-- 
                fmt.Println("wait for thread")
                ok := <-waiters
                fmt.Printf("received thread end: %b\n", ok)
        

这是我运行时的日志:

push entry
push entry
push entry
entry cap: 3
waiters cap: 1
start worker
threads started: 1
wait for thread
worker: name1
worker: name2
worker: name3
throw: all goroutines are asleep - deadlock!

【问题讨论】:

广告“我不明白为什么它从来没有得到服务员的阅读。”:没有最低限度,但完整没有其他人可以理解i> 和可编译的代码。许多死锁纯粹是基于,例如,使用的缓冲通道与非缓冲通道。 【参考方案1】:

简单回答:你需要关闭queue

只有当通道关闭时,双重接收运算符才会返回 false,而您永远不会这样做。所以进程中的循环永远不会退出。顺便说一句,您可以在通道上用 for/range 替换您的 for/if/break。

还有一些其他的围棋习语你应该考虑一下:你读过http://golang.org/doc/effective_go.html 吗?

【讨论】:

@djikstra 我几乎在您发布答案的同时发现了它......非常感谢!我以某种方式假设关闭通道意味着使其无法使用,而不仅仅是不再发生发送。是的,我正在阅读该页面(这是我的第一天去),但我更像是一个“做和被阻止”的学习者,所以在参观之后我开始给我分配一些东西来做例子学习。 没问题。我也倾向于以这种方式学习,只要确保你已经看过它:) 另一个技巧是在形式参数列表中标记通道结束,即func process(queue &lt;-chan *entry, waiters chan&lt;- bool),因为编译器可以告诉你你是否弄乱了它们的用法(在你的例子中你没有)。

以上是关于与通道和 goroutine 同步的主要内容,如果未能解决你的问题,请参考以下文章

基本的 goroutine 和通道模式:一个通道的多个 goroutine

gopl goroutine 和通道

golang-----golang sync.WaitGroup解决goroutine同步

每天一个知识点:Go 语言当中 Channel(通道)有啥特点,需要注意啥?

信号 goroutine 在通道关闭时停止

Go笔记(十四):通道 channel