douzong5057 2018-06-11 20:43
浏览 27
已采纳

并发示例混乱

I’m studying concurrency in more depth with Go. A book I am reading gives the following example, which basically compresses files from command line argument(s).

 package main

 import (
  "compress/gzip"
  "io"
  "os"
 )

 func main() {

     for _, file := range os.Args[1:] {
        compress(file)
     }

 }


 func compress(filename string) error {

     in, err := os.Open(filename)

     if err != nil {
      return err
     }

     defer in.Close()

     out, err := os.Create(filename + ".gz")

     if err != nil {
       return err
     }

     defer out.Close()

     gzout := gzip.NewWriter(out)

     _, err = io.Copy(gzout, in)

     gzout.Close()

     return err
}

The book then explains that if you wanted to process a few hundred files, keeping it like this would definitely be slower than if you were to utilise goroutines, so the following modification is made to the main() function in order to use them:

var wg sync.WaitGroup 
var i int = -1
var file string
for i, file = range os.Args[1:] {
    wg.Add(1)
    go func(filename string) {
       compress(filename)
       wg.Done()
     }(file)
 }
 wg.Wait()
 fmt.Printf("Compressed %d files
", i+1)

It is then noted that the “trickery” with regard to the inline function definition and its parameter (file name), is necessary “because we are executing goroutines in a for loop”.

I guess what I don’t understand is why the above inline function is required to get this working, couldn’t the following be used instead, or am I missing a trick?

for i, file = range os.Args[1:] {
    wg.Add(1)

    go compress(file)

    wg.Done()

 }
 wg.Wait()
 fmt.Printf("Compressed %d files
", i+1)
  • 写回答

1条回答 默认 最新

  • dragon8837 2018-06-11 20:57
    关注

    If you just execute:

    compress(file)
    

    That gets executed in the same goroutine, so until that call finishes, you won't be doing anything else.

    So if you want to process in parallel, then you need to launch a new goroutine by using the go keyword.

    If you do this:

    go compress(file)
    

    Then it will launch a new goroutine for compressing each file.

    But, as soon as the main function launches all goroutines, it will end execution (it will not wait for all goroutines to finish).

    That's why they included the wg calls.

    Since the compress function does not receive a WaitGroup to call the Done over it, they implemented that inline function in order to call wg.Done() right after that goroutine finishes the compression over that file.

    That's the reason for the:

    go func(filename string) {
        compress(filename)
        wg.Done()
    }(file)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 请问如何在openpcdet上对KITTI数据集的测试集进行结果评估?
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路
  • ¥15 phython读取excel表格报错 ^7个 SyntaxError: invalid syntax 语句报错