从通道读取后主通道不退出

时间:2019-06-18 10:00:03

标签: go

我正在学习Go,但是很难理解为什么我的应用无法正常退出。使用下面的代码片段,我得到了正确的结果,但是在读取完最后一个文件之后main永远不会退出。据我所知,这是因为它是某个地方的开放频道,但是我不知道为什么以及如何做到这一点。

此应用程序的要旨是获取一系列PDF文件并读出其中的特定字符串。

package main

import (
    "fmt"
    "os"
)

type PDF struct {
    filename string
    code string
    error  error
}

func (p *PDF) GetCode() string {
    return p.code
}

func main() {
    jobs := make(chan PDF)
    results := make(chan PDF)

    for w := 0; w < 8; w++ {
        go worker(jobs, results)
    }

    // PDF files to read.
    pdfs := []string{"test.pdf", "test2.pdf", "test3.pdf"}

    for _, file := range pdfs {
        go func(file string) {
            jobs <- PDF{filename: file}
        }(file)
    }
    defer close(jobs)

    for i := range results {
        fmt.Printf("%s ", i.GetCode())
    }
}

func worker(jobs <-chan PDF, results chan<- PDF) {
    for file := range jobs {
        fmt.Printf("Processing %s\n", file.filename)
        code, err := outputPdfText(file.filename)
        results <- PDF{filename: file.filename, code: code, error: err}
    }
}

func outputPdfText(inputPath string) (string, error) {
    // Code that reads PDF and returns value
    [...]
}

1 个答案:

答案 0 :(得分:2)

您的代码有死锁。等待处理完成的一个好方法是使用sync.WaitGroup。每次将工作添加到工作程序时加1,然后在goroutine调用wg.done()中表示工作已完成。当等待组上的作业计数为0时,您的代码将正确退出。这是一个示例:

package main

import (
    "fmt"
    "sync"
)

type PDF struct {
    filename string
    code     string
    error    error
}

func (p *PDF) GetCode() string {
    return p.code
}

var wg sync.WaitGroup

func main() {

    jobs := make(chan PDF)
    results := make(chan PDF)

    for w := 0; w < 8; w++ {
        go worker(jobs, results)
    }

    // PDF files to read.
    pdfs := []string{"test.pdf", "test2.pdf", "test3.pdf"}

    defer func() { close(results) }()
    for _, file := range pdfs {
        wg.Add(1)
        jobs <- PDF{filename: file}
    }

    go func() {
        for i := range results {
            fmt.Printf("%s", i.GetCode())
        }
    }()
    wg.Wait()
    close(jobs)
}

func worker(jobs <-chan PDF, results chan<- PDF) {
    for file := range jobs {
        fmt.Printf("Processing %s\n", file.filename)
        code, err := outputPdfText(file.filename)
        results <- PDF{filename: file.filename, code: code, error: err}
        wg.Done()
    }
}

func outputPdfText(inputPath string) (string, error) {
    // Code that reads PDF and returns value
    return "", nil
}