Go 从多个点扫描文件

Go 从多个点扫描文件,go,concurrency,Go,Concurrency,我有一个文件abc.txt,其中包含由换行符分隔的两次打印的字母表 abcdefghijklmopqrstuvwxyz abcdefghijklmopqrstuvwxyz 我想创建一个可以同时解析行的解析器。例如,每行一个goroutine。我目前尝试这样做的过程是: 创建一个频道以接收文本行 为每行创建一个新的扫描仪 将扫描仪和通道传递给goroutine 过程结果在主过程中 但是,只有一个扫描仪返回有用的输出。我尝试执行的代码如下: func main(){ 文件,err:=os.Op

我有一个文件
abc.txt
,其中包含由换行符分隔的两次打印的字母表

abcdefghijklmopqrstuvwxyz
abcdefghijklmopqrstuvwxyz
我想创建一个可以同时解析行的解析器。例如,每行一个goroutine。我目前尝试这样做的过程是:

  • 创建一个频道以接收文本行
  • 为每行创建一个新的扫描仪
  • 将扫描仪和通道传递给goroutine
  • 过程结果在主过程中
但是,只有一个扫描仪返回有用的输出。我尝试执行的代码如下:

func main(){
文件,err:=os.Open(“./squaredness/abc.txt”)
如果错误!=零{
log.Panic(错误)
}
延迟文件。关闭()
仁川:=制造(成串)
对于i:=0;i<2;i++{
扫描器,扫描器
file.Seek(27,0)
scanner.Init(文件)
转到parseLine(fmt.Sprintf(“扫描器%v:,i)”和扫描器,inChan)
}
对于msg:=范围为inChan{
fmt.Println(味精)
}
}
func parseLine(名称字符串,scanner*scanner.scanner,out chan字符串){
对于i:=0;i<26;i++{

out问题似乎是因为文件的两个扫描仪同时移动头部

通过创建2个文件句柄,每个文件句柄都有自己的扫描仪,可以达到预期的效果

package main

import (
    "fmt"
    "log"
    "os"
    "text/scanner"
    "time"
)

func main(){
    var file [2]*os.File
    var err error
    file[0], err = os.Open("./abc.txt")
    file[1], err = os.Open("./abc.txt")
    if err != nil {
        log.Panic(err)
    }
    defer file[0].Close()
    defer file[1].Close()
    var scanner [2]scanner.Scanner
    inChan := make(chan string)


    for i := 0; i < 2; i++ {
        var n int64 = (int64)(i) * 26
        file[i].Seek(n, 0)

        scanner[i].Init(file[i])
        fmt.Println(scanner[0].Pos)
        go parseLine(fmt.Sprintf("Scanner %v:", i), &scanner[i], inChan)
    }

    for msg := range inChan {
        fmt.Println(msg)
    }
}

func parseLine(name string, scanner *scanner.Scanner, out chan string) {
    for i := 0; i < 26; i++ {
        out <- fmt.Sprintf("%s %c", name, scanner.Next())
    }
    time.Sleep(time.Second * 10)
    close(out)
}
主程序包
进口(
“fmt”
“日志”
“操作系统”
“文本/扫描仪”
“时间”
)
func main(){
var文件[2]*os.file
变量错误
文件[0],err=os.Open(“./abc.txt”)
文件[1],err=os.Open(“./abc.txt”)
如果错误!=零{
log.Panic(错误)
}
延迟文件[0]。关闭()
延迟文件[1]。关闭()
变量扫描程序[2]scanner.scanner
仁川:=制造(成串)
对于i:=0;i<2;i++{
变量n int64=(int64)(i)*26
文件[i]。查找(n,0)
扫描程序[i].Init(文件[i])
fmt.Println(扫描仪[0].Pos)
转到parseLine(fmt.Sprintf(“扫描器%v:,i),&扫描器[i],inChan)
}
对于msg:=范围为inChan{
fmt.Println(味精)
}
}
func parseLine(名称字符串,scanner*scanner.scanner,out chan字符串){
对于i:=0;i<26;i++{

out在文件的属性中,只有一个读取位置,而不是每个扫描仪、每个线程或每个goroutine。当您在多个扫描仪对象(或任何其他对象)之间共享一个
os.file
时,从文件读取的第一个goroutine将提升其他扫描器的读取指针。在您的示例中,运行的第一个goroutine将从文件中读取行,第二个goroutine尝试读取,但已在文件末尾

要做到这一点,您只需要读取文件一件事,并且您需要确保发送给goroutines的数据不被共享(您不会重复读取单个缓冲区并将相同的缓冲区发送到任何地方,而下一次读取将覆盖它)

这是一个考虑并发性的好时机,如果这真的值得努力的话。到目前为止,这个程序最慢的部分实际上是从磁盘读取文件,再多的goroutine也不会加快速度。在最佳的单线程程序中,不需要额外的缓冲区拷贝,goroutine synchroni我的直觉是,在这里使用goroutines会使程序更复杂,并且可能会更慢

我对您的程序所做的核心更改是,只有一个东西可以读取文件;例如,您的程序中有一个主循环。该包包含一个对象,该对象可以一次读取一行文件,并生成复制的字符串。我将启动一次工作程序goroutine池,然后向它们提供行:

lines := make(chan string)
file, err := os.Open("./strangeness/abc.txt")
if err != nil { ... }

scan := bufio.NewScanner(file)
for scan.Scan() {
    lines <- scan.Text()
}
close(lines)
行:=make(chan字符串)
文件,err:=os.Open(“./squaredness/abc.txt”)
如果err!=nil{…}
扫描:=bufio.NewScanner(文件)
对于scan.scan(){

请看下面的答案@BBS:如果这就是你想要的,请告诉我