Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File 戈朗:得到;致命错误:所有goroutine都处于休眠状态-死锁“;在waitGroup.Wait()上_File_Go_Concurrency - Fatal编程技术网

File 戈朗:得到;致命错误:所有goroutine都处于休眠状态-死锁“;在waitGroup.Wait()上

File 戈朗:得到;致命错误:所有goroutine都处于休眠状态-死锁“;在waitGroup.Wait()上,file,go,concurrency,File,Go,Concurrency,我正在尝试编写一个代码,对文件进行并发读取,并将内容发布到一个通道 是指向我的代码的链接,代码: func main() { bufferSize := int64(10) f, err := os.Open("tags-c.csv") if err != nil { panic(err) } fileinfo, err := f.Stat() if err != nil { fmt.Println(err)

我正在尝试编写一个代码,对文件进行并发读取,并将内容发布到一个通道

是指向我的代码的链接,代码:

func main() {
    bufferSize := int64(10)
    f, err := os.Open("tags-c.csv")
    if err != nil {
        panic(err)
    }
    fileinfo, err := f.Stat()
    if err != nil {
        fmt.Println(err)
        return
    }
    filesize := int64(fileinfo.Size())
    fmt.Println(filesize)
    routines := filesize / bufferSize
    if remainder := filesize % bufferSize; remainder != 0 {
        routines++
    }
    fmt.Println("Total routines : ", routines)

    channel := make(chan string, 10)
    wg := &sync.WaitGroup{}

    for i := int64(0); i < int64(routines); i++ {
        wg.Add(1)
        go read(i*bufferSize, f, channel, bufferSize, filesize, wg)

    }
    fmt.Println("waiting")
    wg.Wait()
    fmt.Println("wait over")
    close(channel)

    readChannel(channel)
}

func readChannel(channel chan string) {
    for {
        data, more := <-channel
        if more == false {
            break
        }
        fmt.Print(data)
    }
}

func read(seek int64, file *os.File, channel chan string, bufferSize int64, filesize int64, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Println("read :: ", seek)
    var buf []byte
    if filesize < bufferSize {
        buf = make([]byte, filesize)
    } else if (filesize - seek) < bufferSize {
        buf = make([]byte, filesize-seek)
    } else {
        buf = make([]byte, bufferSize)
    }

    n, err := file.ReadAt(buf, seek)
    if err != nil {
        log.Printf("loc %d err: %v", seek, err)
        return
    }
    if n > 0 {
        channel <- string(buf[:n])
        fmt.Println("ret :: ", seek)
    }
}
func main(){
缓冲区大小:=int64(10)
f、 错误:=os.Open(“tags-c.csv”)
如果错误!=零{
恐慌(错误)
}
fileinfo,err:=f.Stat()
如果错误!=零{
fmt.Println(错误)
返回
}
filesize:=int64(fileinfo.Size())
fmt.Println(文件大小)
例程:=文件大小/缓冲区大小
如果余数:=文件大小%bufferSize;余数!=0{
例行程序++
}
fmt.Println(“总例行程序:”,例行程序)
通道:=制造(通道串,10)
wg:=&sync.WaitGroup{}
对于i:=int64(0);i频道问题在于,您希望所有已启动的reader Goroutine都完成,然后才能继续并耗尽它们提供结果的频道

通道被缓冲,最多可容纳10个元素。一旦10个goroutine在其上发送消息,其余的将被阻止,因此它们将永远不会完成(因为从该通道读取只能在它们全部返回后开始:这是死锁)

因此,您应该启动另一个goroutine以与阅读器goroutine同时接收结果:

done := make(chan struct{})
go readChannel(channel, done)

fmt.Println("waiting")
wg.Wait()
fmt.Println("wait over")
close(channel)

// Wait for completion of collecting the results:
<-done
请注意,我使用了一个
done
通道,因此主goroutine也将等待goroutine接收结果完成


另外请注意,由于在大多数情况下,磁盘IO是瓶颈,而不是CPU,而且从多个goroutine发送和接收结果也会有一些开销,因此很可能无法看到从多个goroutine同时读取文件的任何改进。

问题在于,您需要所有已启动的rea在您继续并耗尽他们交付结果的渠道之前,请让goroutines完成

通道被缓冲,最多可容纳10个元素。一旦10个goroutine在其上发送消息,其余的将被阻止,因此它们将永远不会完成(因为从该通道读取只能在它们全部返回后开始:这是死锁)

因此,您应该启动另一个goroutine以与阅读器goroutine同时接收结果:

done := make(chan struct{})
go readChannel(channel, done)

fmt.Println("waiting")
wg.Wait()
fmt.Println("wait over")
close(channel)

// Wait for completion of collecting the results:
<-done
请注意,我使用了一个
done
通道,因此主goroutine也将等待goroutine接收结果完成


还要注意的是,由于在大多数情况下,磁盘IO是瓶颈,而不是CPU,而且从多个goroutine发送和接收结果也会有一些开销,因此您很可能看不到从多个goroutine同时读取文件的任何改进。

谢谢@icza。我真愚蠢,错过了调用readCh在一个新的go例程中进行退火。关于读取操作,seek将读取指针设置为指定的偏移量,readAt只读取指定偏移量w.r.t处的值,如果我没有错的话。所以基本上我所做的是偏移量为0,缓冲区为100,所以从文件中读取的前100个字符偏移量为1*100,缓冲区为100,所以接下来读取的100个字符…等等on@PraveenKamath你说得对,我错了。我以为你是用
file.read()读取文件的
。请参阅编辑后的答案。谢谢@icza。我太蠢了,在新的go例程中错过了调用readChannel。关于读取操作,seek将读取指针设置为指定的偏移量,readAt只读取指定偏移量的值w.r.t文件的开头,如果我没有错的话。所以基本上我所做的是偏移量为0,缓冲区为100,所以前100个字符是从文件中读取的,偏移量是1*100,缓冲区是100,所以接下来要读取100个字符…等等on@PraveenKamath你说得对,我错了。我以为你是用
file.read()
读取文件的。请参阅编辑后的答案。