gpt4 book ai didi

go - 并发逐行读取文件

转载 作者:IT王子 更新时间:2023-10-29 02:02:26 29 4
gpt4 key购买 nike

我想做什么

GetLine 中,我尝试使用 bufio.Scanner 逐行解析文件,并尝试并发。在获取每一行中的文本之后,我通过 string channel 将其发送给调用者(main 函数)。除了值,我还发送错误和完成标志(通过 done channel )。因此,这应该能够在处理当前行时获取新行以在单独的 goroutine 中处理。

我实际做了什么

var READCOMPLETE = errors.New("Completed Reading")

func main() {

filename := flag.String("filename", "", "The file to parse")
flag.Parse()

if *filename == "" {
log.Fatal("Provide a file to parse")
}

fmt.Println("Getting file")

names := make(chan string)
readerr := make(chan error)
done := make(chan bool)

go GetLine(*filename, names, readerr, done)

for {
select {
case name := <-names:
// Process each line
fmt.Println(name)

case err := <-readerr:
log.Fatal(err)

case <-done:
// close(names)
// close(readerr)
break
}
}

fmt.Println("Processing Complete")
}

func GetLine(filename string, names chan string, readerr chan error, done chan bool) {
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
names <- scanner.Text()
//fmt.Println(scanner.Text())
}

if err := scanner.Err(); err != nil {
readerr <- err
}

done <- true
}

运行的收获

运行时错误: fatal error :所有 goroutines 都睡着了 - 死锁!

我尝试修复了什么?

看完this回答有关错误消息的问题,我尝试在 select 语句的最后一个子句中关闭 channel namesreaderr,如评论中所示。但是,该程序仍然崩溃并显示一条日志消息。我无法进一步修复它,如有任何帮助,我将不胜感激。
欢迎提供学习资源。

P.S:我对 GoLang 比较陌生,仍在学习如何在 Go 中使用 CSP 并发模型。事实上,这是我第一次尝试编写同步并发程序。

最佳答案

select 中的 break 语句从 select 中跳出。应用程序必须在完成后跳出 for 循环。使用标签跳出 for 循环:

loop:
for {
select {
case name := <-names:
// Process each line
fmt.Println(name)

case err := <-readerr:
log.Fatal(err)

case <-done:
// close(names)
// close(readerr)
break loop
}
}

可以通过删除 done channel 来简化代码。

func main() {

filename := flag.String("filename", "", "The file to parse")
flag.Parse()

if *filename == "" {
log.Fatal("Provide a file to parse")
}

fmt.Println("Getting file")

names := make(chan string)
readerr := make(chan error)

go GetLine(*filename, names, readerr)

loop:
for {
select {
case name := <-names:
// Process each line
fmt.Println(name)

case err := <-readerr:
if err != nil {
log.Fatal(err)
}
break loop
}
}

fmt.Println("Processing Complete")
}

func GetLine(filename string, names chan string, readerr chan error) {
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
names <- scanner.Text()
}
readerr <- scanner.Err()
}

在这个具体的例子中,可以重构代码以将接收名称与接收错误分开。

func main() {
filename := flag.String("filename", "", "The file to parse")
flag.Parse()

if *filename == "" {
log.Fatal("Provide a file to parse")
}

fmt.Println("Getting file")

names := make(chan string)
readerr := make(chan error)

go GetLine(*filename, names, readerr)

for name := range names {
fmt.Println(name)
}
if err := <-readerr; err != nil {
log.Fatal(err)
}

fmt.Println("Processing Complete")
}

func GetLine(filename string, names chan string, readerr chan error) {
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
names <- scanner.Text()
}
close(names) // close causes range on channel to break out of loop
readerr <- scanner.Err()
}

关于go - 并发逐行读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48026595/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com