Канал никогда не умирает, хотя и закрыт

В следующем коде я пытаюсь записать все файлы, отправленные на канал 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

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

Это вызывает тупик в обоих случаях, когда есть и нет ошибки, даже если я закрываю оба канала, когда закончу с ними?


person duck    schedule 05.06.2017    source источник
comment
В качестве комментария, поскольку это не связано с q - поскольку WriteC уже вызывается как горутина, почему она запускает другую горутину для вызова writeWorker?   -  person Adrian    schedule 05.06.2017
comment
Поскольку вы можете добавить несколько экземпляров writeC в другие части вашего кода, которые не связаны друг с другом.   -  person duck    schedule 05.06.2017


Ответы (1)


Вы читаете только от operationOutcomes до writeOpCount раз, хотя в writeWorker каждое выполнение может привести к записи до 3 сообщений на этот канал (ни один из ваших случаев ошибки не приводит к возврату функции, чтобы она продолжала обработку). Поскольку он не буферизован и его перестают читать, в какой-то момент рабочие, пишущие в него, больше не могут добавлять сообщения и блокируются навсегда.

Кроме того, поскольку вы вызываете WriteC только один раз и он не зацикливается, он будет читать и обрабатывать только одно сообщение из inputs. Если writeOpCount > 1, то он навсегда заблокируется в первом цикле, когда попытается поставить в очередь второе сообщение.

person Adrian    schedule 05.06.2017
comment
я действительно заметил это и попытался добавить операторы return после каждого нажатия на канал. Однако это не решает проблему. - person duck; 05.06.2017
comment
Обновлено - обнаружена вторая проблема. - person Adrian; 05.06.2017
comment
большое спасибо. вторая проблема решила мою проблему. - person duck; 05.06.2017