I'm building an app to run a command every time the code changes. I'm using a fsnotify
for this feature. But, I can't understand how it is waiting a main goroutine.
I found that using sync.WaitGroup
is more idiomatic, but I'm curious how done chan bool makes a goroutine is waiting in fsnotify
example code.
I've tried to remove done
in the example code of fsnotify
, but it's not waiting a goroutine, just is exited.
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
done := make(chan bool)
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
log.Println("event:", event)
if event.Op&fsnotify.Write == fsnotify.Write {
log.Println("modified file:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("error:", err)
}
}
}()
err = watcher.Add("/tmp/foo")
if err != nil {
log.Fatal(err)
}
<-done
As per my study, I found an answer from one guy in reddit.com. This is kind of trick though, using <-done
makes the main goroutine waiting an any value from chan done, eventually this app keeps running for fsnotify
to watch and send a event to the main goroutine.
I'm not entirely sure what you're asking, but there's a subtle bug in the code you've provided.
A done
channel is a common way to block until an action completes. It is used like this:
done := make(chan X) // Where X is any type
go func() {
// Some logic, possibly in a loop
close(done)
}()
// Other logic
<-done // Wait for `done` to be closed
The type of the channel is unimportant, as no data is (necissarily) sent over the channel, so bool
works, but struct{}
is more idiomatic, as it indicates that no data can be sent.
Your example almost does this, except that it never calls close(done)
. This is a bug. It means that the code will always wait forever at <-done
, thus negating the entire purpose of a done channel. Your example code will never exit.
This means the code, as you have provided, could be also written as:
go func() {
// Do stuff
}()
// Do other stuff
<Any code that blocks forever>
Because there are countless ways to block forever--none of them ever useful in practice--the channel in your example is not needed.