gpt4 book ai didi

multithreading - 工作池模式 - 死锁

转载 作者:行者123 更新时间:2023-12-01 22:40:13 25 4
gpt4 key购买 nike

等待任务模式是池化模式的基础模式。虾虎鱼示例 code看起来不对,因为这段代码使用的是缓冲 channel 。

在下面的代码中:

package main

import (
"fmt"
"runtime"
)

// pooling: You are a manager and you hire a team of employees. None of the new
// employees know what they are expected to do and wait for you to provide work.
// When work is provided to the group, any given employee can take it and you
// don't care who it is. The amount of time you wait for any given employee to
// take your work is unknown because you need a guarantee that the work your
// sending is received by an employee.
func pooling() {
jobCh := make(chan int) // signalling data on channel with guarantee - unbuffered
resultCh := make(chan int) // signalling data on channel with guarantee - unbuffered

workers := runtime.NumCPU() // 4 workers
for worker := 0; worker < workers; worker++ {
go func(emp int) {
var p int
for p = range jobCh {
fmt.Printf("employee %d : recv'd signal : %d\n", emp, p) // do the work
}
fmt.Printf("employee %d : recv'd shutdown signal\n", emp) // worker is signaled with closed state channel
resultCh <- p * 2
}(worker)
}

const jobs = 6
for jobNum := 1; jobNum <= jobs; jobNum++ {
jobCh <- jobNum
fmt.Println("manager : sent signal :", jobNum)
}

close(jobCh)
fmt.Println("manager : sent shutdown signal")

for a := 1; a <= jobs; a++ { //cannot range on 'resultCh'
fmt.Println("Result received: ", <-resultCh)
}
fmt.Println("-------------------------------------------------------------")
}
func main() {
pooling()
}

经理( pooling())没有收到来自 4 个 worker (雇员)的所有六个结果,如下所示,
$ uname -a 
Linux user 4.15.0-99-generic #100-Ubuntu SMP Wed Apr 22 20:32:56 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$
$ go version
go version go1.14.1 linux/amd64
$
$ go install github.com/myhub/cs61a
$
$
$ bin/cs61a
manager : sent signal : 1
manager : sent signal : 2
manager : sent signal : 3
employee 3 : recv'd signal : 3
employee 3 : recv'd signal : 4
manager : sent signal : 4
manager : sent signal : 5
employee 3 : recv'd signal : 5
employee 3 : recv'd signal : 6
manager : sent signal : 6
manager : sent shutdown signal
employee 3 : recv'd shutdown signal
employee 2 : recv'd signal : 2
Result received: 12
employee 0 : recv'd signal : 1
employee 0 : recv'd shutdown signal
employee 2 : recv'd shutdown signal
Result received: 2
Result received: 4
employee 1 : recv'd shutdown signal
Result received: 0
fatal error: all goroutines are asleep - deadlock!


goroutine 1 [chan receive]:
main.pooling()
/home/../src/github.com/myhub/cs61a/Main.go:40 +0x25f
main.main()
/home/../src/github.com/myhub/cs61a/Main.go:45 +0x20
$
$
$ bin/cs61a
manager : sent signal : 1
employee 0 : recv'd signal : 1
manager : sent signal : 2
manager : sent signal : 3
manager : sent signal : 4
employee 3 : recv'd signal : 2
manager : sent signal : 5
manager : sent signal : 6
employee 2 : recv'd signal : 4
employee 2 : recv'd shutdown signal
employee 0 : recv'd signal : 5
manager : sent shutdown signal
Result received: 8
employee 0 : recv'd shutdown signal
Result received: 10
employee 1 : recv'd signal : 3
employee 1 : recv'd shutdown signal
Result received: 6
employee 3 : recv'd signal : 6
employee 3 : recv'd shutdown signal
Result received: 12
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.pooling()
/home/user/../github.com/myhub/cs61a/Main.go:40 +0x25f
main.main()
/home/user/../github.com/myhub/cs61a/Main.go:45 +0x20

编辑:

根据@Mark 评论,移动 resultCh <- p * 2进入循环会导致下面的死锁,这是有道理的,因为所有的 goroutine 都被阻塞了。缓冲 channel ( resultCh)是否有助于解决此问题?但缓冲 channel 不保证信号数据..
$ go install github.com/myhub/cs61a
$ bin/cs61a
manager : sent signal : 1
manager : sent signal : 2
manager : sent signal : 3
manager : sent signal : 4
employee 1 : recv'd signal : 2
employee 2 : recv'd signal : 3
employee 0 : recv'd signal : 1
employee 3 : recv'd signal : 4
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.pooling()
/home/user/../myhub/cs61a/Main.go:33 +0xfb
main.main()
/home/user/../myhub/cs61a/Main.go:46 +0x20

goroutine 6 [chan send]:
main.pooling.func1(0xc00001e0c0, 0xc00001e120, 0x0)
/home/user/../myhub/cs61a/Main.go:24 +0x136
created by main.pooling
/home/user/../myhub/cs61a/Main.go:20 +0xb7

goroutine 7 [chan send]:
main.pooling.func1(0xc00001e0c0, 0xc00001e120, 0x1)
/home/user/../myhub/cs61a/Main.go:24 +0x136
created by main.pooling
/home/user/../myhub/cs61a/Main.go:20 +0xb7

goroutine 8 [chan send]:
main.pooling.func1(0xc00001e0c0, 0xc00001e120, 0x2)
/home/user/../myhub/cs61a/Main.go:24 +0x136
created by main.pooling
/home/user/../myhub/cs61a/Main.go:20 +0xb7

goroutine 9 [chan send]:
main.pooling.func1(0xc00001e0c0, 0xc00001e120, 0x3)
/home/user/../myhub/cs61a/Main.go:24 +0x136
created by main.pooling
/home/user/../myhub/cs61a/Main.go:20 +0xb7
$
$
$

  • 为什么是 pooling()无法收到所有 worker 的结果?
  • 经理只收到 6 个结果中的 4 个。收到的结果之一是零(Result received: 0),数据在 resultCh 上发送总是应该是非零的,为什么 resultCh收到零值?看起来像 resultCh已经关闭。

  • 注意: resultCh 的正确工作不是工作池模式的责任的一部分。工作池模式仅确保使用 jobCh 将工作成功提交给员工

    最佳答案

    Why is pooling() not able to receive results from all workers?



    goroutine(s) ( for p = range jobCh) 中的循环将处理所有请求。但是发送到 resultCh 的代码位于循环之外,因此只会在每个 go 例程中执行一次(在循环完成后)。

    这是根据@Marks 评论;您对范围的回答是正确的,但无关紧要。 for 循环将遍历 channel 上的项目;当 channel 关闭时,循环结束, p将包含上一次迭代处理的值(如果有)并发送到 resultCh .

    这意味着 resultCh将为每个 go 例程发送一个值(根据您的代码中的注释在您的情况下发送四个值)。如果要将值发布到 resultCh对于 jobCh 上收到的每个值那么您需要将发送移动到循环中( playground):
    var p int
    for p = range jobCh {
    fmt.Printf("employee %d : recv'd signal : %d\n", emp, p) // do the work
    resultCh <- p * 2
    }
    fmt.Printf("employee %d : recv'd shutdown signal\n", emp)

    Manager is receiving only 4 results out of 6. One of the result received is zero (Result received: 0), data sent on resultCh is always supposed to be non-zero, Why does resultCh receive zero value? It looks like resultCh is closed.



    您无法预测每个 goroutine 将处理多少个作业(并且日志显示这在您的两次运行之间有所不同)。从您的日志中,我们可以知道哪个例程处理了哪些作业::
    Employee 0: 1
    Employee 1:
    Employee 2: 2
    Employee 3: 3, 4, 5, 6

    您会注意到员工 1 没有处理任何工作。这意味着员工循环 for p = range jobCh没有给 p 分配任何东西就终止了因此, resultCh <- p * 2将 0(int 的默认值)发送到 resultCh (根据@Shudipta Sharma 的评论)。

    关于multithreading - 工作池模式 - 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61859010/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com