使用 channnels 的 goroutines 同步问题

我正在使用以下代码来同步goroutines。最近在调查一个错误时,我发现下面的代码并不总是有效。大约五分之一的失败。频道在我的频道之前获取消息。我能够在本地(而不是在go-playground)和k8s环境中始终如一地重现此问题。作为一种解决方法,我现在使用同步。quitoutsync.Map


有没有办法修复下面的代码?


package main


import (

    "fmt"

    "io/ioutil"

    "log"

    "os"

    "path"

    "sync"

    "sync/atomic"

    "time"

)


func main() {

    //test setup

    filePaths := []string{

        path.Join(os.TempDir(), fmt.Sprint("f1-", time.Now().Nanosecond())),

        path.Join(os.TempDir(), fmt.Sprint("f2-", time.Now().Nanosecond())),

        path.Join(os.TempDir(), fmt.Sprint("f3-", time.Now().Nanosecond())),

        path.Join(os.TempDir(), fmt.Sprint("f4-", time.Now().Nanosecond())),

        path.Join(os.TempDir(), fmt.Sprint("f5-", time.Now().Nanosecond())),

        path.Join(os.TempDir(), fmt.Sprint("f6-", time.Now().Nanosecond())),

    }

    for _, filePath := range filePaths {

        f, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)

        if err != nil {

            log.Fatal(err)

        }

        _, err = f.WriteString("There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.")

        if err != nil {

            log.Fatal(err)

        }

        err = f.Close()

        if err != nil {

            log.Fatal(err)

        }

    }


富国沪深
浏览 82回答 1
1回答

紫衣仙女

收到退出时,输出通道可以包含值。通过制作无缓冲通道进行修复:out&nbsp;:=&nbsp;make(chan&nbsp;[]byte)这可确保在退出之前收到从工作线程发送的值:在无缓冲信道上发送/接收发生在调用wg.Done()所有电话在返回之前发生wg.Done()wg.Wait()wg.Wait()在将值发送到 之前返回quit因此,在将值发送到 之前,将从 接收值。outquit另一种方法是关闭通道,向结果收集器发出工作线程已完成的信号:outfunc getContents(fileNames []string) ([][]byte, error) {&nbsp; &nbsp; wg := sync.WaitGroup{}&nbsp; &nbsp; var responseBytes [][]byte&nbsp; &nbsp; out := make(chan []byte)&nbsp; &nbsp; var opsFileRead uint64&nbsp; &nbsp; var opsChannelGot uint64&nbsp; &nbsp; for _, fileName := range fileNames {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func(fName string, out chan []byte, wg *sync.WaitGroup) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data, err := ioutil.ReadFile(fName)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out <- data&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; atomic.AddUint64(&opsFileRead, 1)&nbsp; &nbsp; &nbsp; &nbsp; }(fileName, out, &wg)&nbsp; &nbsp; }&nbsp; &nbsp; // Close out after workers are done.&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(out)&nbsp; &nbsp; }()&nbsp; &nbsp; // Loop over outputs until done.&nbsp; &nbsp; for bts := range out {&nbsp; &nbsp; &nbsp; &nbsp; if len(bts) > 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; atomic.AddUint64(&opsChannelGot, 1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; responseBytes = append(responseBytes, bts)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Printf("I quit, i read %d, i got %d\n", opsFileRead, opsChannelGot)&nbsp; &nbsp; return responseBytes, nil}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go