【问题标题】:Channel never dies although closed频道虽然关闭但永不消亡
【发布时间】:2017-06-05 12:24:48
【问题描述】:

在下面的代码中,我试图编写发送到inputs 频道的所有文件,并通过operationOutcomes 频道发送相应的响应

ma​​in.go

package main

import(
    lr "github.com/fabulousduck/librarian"
    "fmt"
)

func main() {
    writeOpCount := 100;
    operationOutcomes, inputs := make(chan lr.WriteOpResponse), make(chan lr.WriteOp)
    go lr.WriteC(inputs, operationOutcomes)

    for i := 0; i < writeOpCount; i++ {
        inputs <- lr.WriteOp{ Dest: `../exampleFiles/createdFiles/{i}.txt`, Content: `Invoice #{i}` }
    }

    close(inputs)  

    for i := 0; i < writeOpCount; i++ {
        writeResult := <-operationOutcomes
        fmt.Println("Response from write operation : ", writeResult.Msg, "err ", writeResult.Err, "bytes written : ", writeResult.BytesWritten)
    }

    close(operationOutcomes)
}

librarian.go 包库管理员

import(
    "os"
    "fmt"
)

type WriteOp struct {
    Dest, Content string
}

type WriteOpResponse struct {
    Msg error
    Err bool
    BytesWritten int
}

func WriteC (inputChannel <-chan WriteOp, outputChannel chan<- WriteOpResponse) {
    workOp :=  <-inputChannel
    go writeWorker(workOp, outputChannel)
}

func writeWorker (job WriteOp, outGoing chan<- WriteOpResponse) {
    file, err := os.OpenFile(job.Dest, os.O_RDWR, 0666)
    if err != nil {
        fmt.Println("err : ", err)
        outGoing <- WriteOpResponse{ Msg: err, Err: true, BytesWritten: 0 }
    }
    bytesWritten , err := file.WriteString(job.Content)
    if err != nil {
        outGoing <- WriteOpResponse{ Msg: err, Err: true, BytesWritten: 0 }
    }
    outGoing <- WriteOpResponse{ Msg: nil, Err: false, BytesWritten: bytesWritten } 
}

这在两种情况下都会引发死锁,无论是否存在错误,即使我在完成处理后关闭了两个通道?

【问题讨论】:

  • 作为注释,因为它与 q 无关 - 由于 WriteC 已经作为 goroutine 调用,为什么它会启动另一个 goroutine 来调用 writeWorker
  • 因为您可能希望在代码的其他不相关部分中添加多个 writeC 实例。

标签: go goroutine channels


【解决方案1】:

您只能从 operationOutcomes 读取到 writeOpCount 次,即使在 writeWorker 中,每次执行都可能导致在该通道上写入最多 3 条消息(您的任何错误情况都不会导致函数返回,以它继续处理)。因为它没有缓冲并且停止被读取,所以在某些时候写入它的工作人员不能再添加消息并因此永远锁定。

此外,由于您只调用一次WriteC 并且它不会循环,因此它只会读取和处理来自inputs 的一条消息。如果writeOpCount > 1,那么当它尝试对第二条消息进行排队时,它将在第一个循环中永远锁定。

【讨论】:

  • 我确实注意到了这一点,并尝试在每次推送到频道后添加return 语句。然而,这并不能解决问题。
  • 已更新 - 发现了第二个问题。
  • 非常感谢。第二个问题解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 2012-08-04
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 2011-10-25
相关资源
最近更新 更多