亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

恐慌:在 foor 循環中運行 go routine 時在關閉的通道上發送

恐慌:在 foor 循環中運行 go routine 時在關閉的通道上發送

Go
守候你守候我 2023-03-15 13:52:32
我正在嘗試制作 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是不是我在錯誤的時間點關閉了頻道?
查看完整描述

1 回答

?
桃花長相依

TA貢獻1860條經驗 獲得超8個贊

此代碼的 2 個主要問題是

  1. 您只需要在完成后關閉頻道wg.Wait()。您可以在單獨的 goroutine 中執行此操作,如下所示

  2. 由于pathsearchPaths func 中的 var 作為 for 循環邏輯的一部分被多次重新分配,因此not a good practice to use that var directly in the goroutines更好的方法是將其作為參數傳遞。

package main


import (

    "fmt"

    "io/fs"

    "io/ioutil"

    "log"

    "os"

    "path/filepath"

    "strings"

    "sync"

)


type SearchResult struct {

    line       string

    lineNumber int

}


type Display struct {

    filePath string

    SearchResult

}


var wg sync.WaitGroup


func (d Display) PrettyPrint() {

    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) {

    if strings.Contains(line, pattern) {

        return SearchResult{lineNumber: lineNumber + 1, line: line}, true

    }

    return SearchResult{}, false

}


func splitIntoLines(file string) []string {

    lines := strings.Split(file, "\n")

    return lines

}


func fileFromPath(path string) string {

    fileContent, err := ioutil.ReadFile(path)


    if err != nil {

        log.Fatal(err)

    }


    return string(fileContent)

}


func getRecursiveFilePaths(inputDir string) []string {

    var paths []string

    err := filepath.Walk(inputDir, func(path string, info fs.FileInfo, err error) error {

        if err != nil {

            fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err)

            return err

        }

        if !info.IsDir() {

            paths = append(paths, path)

        }

        return nil

    })

    if err != nil {

        fmt.Printf("Error walking the path %q: %v\n", inputDir, err)

    }

    return paths

}


func searchPaths(paths []string, pattern string) chan Display {

    out := make(chan Display)

    for _, path := range paths {

        wg.Add(1)

        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

            defer w.Done()

            for _, display := range searchFile(p, pattern) {

                out <- display

            }

        }(path, &wg)

    }

    return out

}


func searchFile(path string, pattern string) []Display {

    var out []Display

    input := fileFromPath(path)

    lines := splitIntoLines(input)

    for index, line := range lines {

        if searchResult, ok := searchLine(pattern, line, index); ok {

            out = append(out, Display{path, searchResult})

        }

    }

    return out

}


func main() {

    pattern := os.Args[1]

    dirPath := os.Args[2]


    paths := getRecursiveFilePaths(dirPath)


    out := searchPaths(paths, pattern)


    go func(){

        wg.Wait() // waiting before closing the channel

        close(out)

    }()

    

    count := 0

    for d := range out {

        fmt.Println(count)

        d.PrettyPrint()

        count += 1

    }


}


查看完整回答
反對 回復 2023-03-15
  • 1 回答
  • 0 關注
  • 105 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號