渠道仅接受一次价值-Golang

I am just starting out with go. Here is what I am trying to achieve from the following code.

Main function creates 5 threads for searchAndLog(). This function accepts a channel through which it will receive a path to a directory and it will search for a file called ".DS_Store" and then do something with it.

main function then creates another thread for "file path.Walk()". This thread will walk directory passed to it and for each directory which it comes across (in walkFunc()) it will execute select statement passing directory path to one of the 5 threads.

But when I run this program, first five directories which "filepath.Walk()" encounters it passes it to five threads, but once it has passed a directory to each of the threads once, it stops. Channels dir[0] to dir[5] in select won't accept value second time around.

What am I doing wrong?

package main

// A simple multithreaded program to calculate how many
// and total disk space occupyed by all ".DS_Store" files.
// It also logs the location of each file along with its
// size

import (
  "fmt"
  "io/ioutil"
  "os"
  "flag"
  "path/filepath"
)

// Returns true if path is a directory otherwise false
func isDirectory(path string) bool {
  file, err := os.Open(path)
  if err != nil {
    fmt.Println(err)
    return false
  }
  defer file.Close()
  fi, err := file.Stat()
  if err != nil {
    fmt.Println(err)
    return false
  }
  return (fi.Mode()).IsDir()
}

func main() {

  // Command line flag to pass in how many threads to swapn
  var numThreads int
  flag.IntVar(&numThreads, "t", 5, "number of threads")
  flag.Parse()
  fmt.Println("numThreads: ", numThreads)

  // 5 Channels for 5 threads
  var dir [5]chan string
  for i, _ := range dir {
    dir[i] = make(chan string)
  }

  // This is the function that will be passed to filepath.Walk()
  // "select" will be executed only if path points to directory
  walkFunc := func(path string, info os.FileInfo, err error) error {
    fmt.Println("Visited: ", path)
    if isDirectory(path) {
      select {
        case dir[0] <- path:
          fmt.Println("Thread: 1")
        case dir[1] <- path:
          fmt.Println("Thread: 2")
        case dir[2] <- path:
          fmt.Println("Thread: 3")
        case dir[3] <- path:
          fmt.Println("Thread: 4")
        case dir[4] <- path:
          fmt.Println("Thread: 5")
        }
    }
    return nil
  }

  // Create 5 threads of searchAndLog()
  for i := 0; i < numThreads; i++ {
    go searchAndLog(dir[i], i)
  }

  go filepath.Walk("/Users/nikhil/Workspace", walkFunc)

  var input string
  fmt.Scanln(&input)
}

// id is passed to identify the thread in the println statements
func searchAndLog(dirpath chan string, id int) {
  directory := <- dirpath
  fmt.Println("Thread # ", id + 1, directory)
  files, _ := ioutil.ReadDir(directory)
  for _, f := range files {
    if f.Name() == ".DS_Store" {
      fmt.Println("Thread # ", id + 1, f.Size())
    }
  }
}

EDIT: As Damsham pointed out as threads exits after accepting value once. Replace thread creation loop with code that he suggested to fix the code.

Because once searchAndLog receives something on the channel, it will do its stuff and exit. Therefore after 5 directories, all of your goroutines that were running searchAndLog are now gone. Try this:

// Create 5 threads of searchAndLog()
for i := 0; i < numThreads; i++ {
  go func(i int) {
     for {
        searchAndLog(dir[i], i)
     }
  }(i)
}