恐慌:在 foor 循环中运行 go routine 时在关闭的通道上发送

我正在尝试制作 grep 的并发版本。该程序遍历目录/子目录并将任何匹配的字符串返回给提供的模式。

searchPaths一旦我拥有所有要搜索的文件(请参阅功能),我将尝试同时运行文件搜索。最初我得到:

fatal error: all goroutines are asleep - deadlock

直到我在 searchPaths 的末尾添加了close(out),它现在返回:

Panic: Send on a closed channel when running go routine in foor loop

我正在尝试实现类似于:

https://go.dev/blog/pipelines#fan-out-fan-in

是不是我在错误的时间点关闭了频道?


守候你守候我
浏览 117回答 1
1回答

桃花长相依

此代码的 2 个主要问题是您只需要在完成后关闭频道wg.Wait()。您可以在单独的 goroutine 中执行此操作,如下所示由于pathsearchPaths func 中的 var 作为 for 循环逻辑的一部分被多次重新分配,因此not a good practice to use that var directly in the goroutines更好的方法是将其作为参数传递。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "io/fs"&nbsp; &nbsp; "io/ioutil"&nbsp; &nbsp; "log"&nbsp; &nbsp; "os"&nbsp; &nbsp; "path/filepath"&nbsp; &nbsp; "strings"&nbsp; &nbsp; "sync")type SearchResult struct {&nbsp; &nbsp; line&nbsp; &nbsp; &nbsp; &nbsp;string&nbsp; &nbsp; lineNumber int}type Display struct {&nbsp; &nbsp; filePath string&nbsp; &nbsp; SearchResult}var wg sync.WaitGroupfunc (d Display) PrettyPrint() {&nbsp; &nbsp; fmt.Printf("Line Number: %v\nFilePath: %v\nLine: %v\n\n", d.lineNumber, d.filePath, d.line)}func searchLine(pattern string, line string, lineNumber int) (SearchResult, bool) {&nbsp; &nbsp; if strings.Contains(line, pattern) {&nbsp; &nbsp; &nbsp; &nbsp; return SearchResult{lineNumber: lineNumber + 1, line: line}, true&nbsp; &nbsp; }&nbsp; &nbsp; return SearchResult{}, false}func splitIntoLines(file string) []string {&nbsp; &nbsp; lines := strings.Split(file, "\n")&nbsp; &nbsp; return lines}func fileFromPath(path string) string {&nbsp; &nbsp; fileContent, err := ioutil.ReadFile(path)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; return string(fileContent)}func getRecursiveFilePaths(inputDir string) []string {&nbsp; &nbsp; var paths []string&nbsp; &nbsp; err := filepath.Walk(inputDir, func(path string, info fs.FileInfo, err error) error {&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if !info.IsDir() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; paths = append(paths, path)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; })&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("Error walking the path %q: %v\n", inputDir, err)&nbsp; &nbsp; }&nbsp; &nbsp; return paths}func searchPaths(paths []string, pattern string) chan Display {&nbsp; &nbsp; out := make(chan Display)&nbsp; &nbsp; for _, path := range paths {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func(p string, w *sync.WaitGroup) { // as path var is changing value in the loop, it's better to provide it as a argument in goroutine&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer w.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for _, display := range searchFile(p, pattern) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out <- display&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }(path, &wg)&nbsp; &nbsp; }&nbsp; &nbsp; return out}func searchFile(path string, pattern string) []Display {&nbsp; &nbsp; var out []Display&nbsp; &nbsp; input := fileFromPath(path)&nbsp; &nbsp; lines := splitIntoLines(input)&nbsp; &nbsp; for index, line := range lines {&nbsp; &nbsp; &nbsp; &nbsp; if searchResult, ok := searchLine(pattern, line, index); ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out = append(out, Display{path, searchResult})&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return out}func main() {&nbsp; &nbsp; pattern := os.Args[1]&nbsp; &nbsp; dirPath := os.Args[2]&nbsp; &nbsp; paths := getRecursiveFilePaths(dirPath)&nbsp; &nbsp; out := searchPaths(paths, pattern)&nbsp; &nbsp; go func(){&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait() // waiting before closing the channel&nbsp; &nbsp; &nbsp; &nbsp; close(out)&nbsp; &nbsp; }()&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; count := 0&nbsp; &nbsp; for d := range out {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(count)&nbsp; &nbsp; &nbsp; &nbsp; d.PrettyPrint()&nbsp; &nbsp; &nbsp; &nbsp; count += 1&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go