频道虽然关闭,但永不消失。

huangapple go评论73阅读模式
英文:

Channel never dies although closed

问题

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

main.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
package librarian

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 } 
}

无论是否出现错误,这两种情况都会导致死锁,即使我在使用完它们后关闭了两个通道。

英文:

In the following code, i am trying to write all files that are sent to the inputs channel and send a corresponding response over the operationOutcomes channel

main.go

package main

import(
    lr &quot;github.com/fabulousduck/librarian&quot;
    &quot;fmt&quot;
)

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

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

    close(inputs)  

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

    close(operationOutcomes)
}

librarian.go
package librarian

import(
    &quot;os&quot;
    &quot;fmt&quot;
)

type WriteOp struct {
    Dest, Content string
}

type WriteOpResponse struct {
    Msg error
    Err bool
    BytesWritten int
}

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

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

This throws a deadlock in both cases when there is and isn't an error, even though i am closing both channels when i am done with them ?

答案1

得分: 1

你只读取了operationOutcomeswriteOpCount次数,即使在writeWorker中,每次执行都可能导致在该通道上写入多达3条消息(没有错误情况会导致函数返回,因此它会继续处理)。由于它是无缓冲的并且停止被读取,所以在某个时刻,写入该通道的工作线程将无法再添加消息,从而永久锁定。

此外,由于你只调用了一次WriteC且没有循环,它只会从inputs中读取和处理一条消息。如果writeOpCount大于1,则在第一次循环中尝试排队第二条消息时,它将永久锁定。

英文:

You only read from operationOutcomes up to writeOpCount times, even though in writeWorker each execution can result in up to 3 messages being written on that channel (none of your error cases causes the function to return, to it continues processing). Because it's unbuffered and it stops being read, at some point the workers writing to it can no longer add messages and so lock forever.

Also, since you only call WriteC once and it does not loop, it will only ever read and process one message from the inputs. If writeOpCount is > 1, then it will lock forever within the first loop when it tries to queue a second message.

huangapple
  • 本文由 发表于 2017年6月5日 20:24:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/44368901.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定