ゴルーチンをつかってスレッドを作って非同期にするとき、そのスレッドをチャネル経由で制御するデモ。 気が向いたら説明を付加するけど、だいたいわかると思う。
- LogWriter.go
- main.go
package main | |
import "os" | |
type logWriterCtl int | |
const ( | |
reopenCtl logWriterCtl = iota // reopen file | |
closeCtl // close file | |
) | |
// LogWriter represents single-thread asynchronus log writer thread. | |
type LogWriter struct { | |
path string | |
file *os.File | |
logCh chan string | |
ctlCh chan logWriterCtl | |
closeResultCh chan bool | |
} | |
// NewLogWriter returns initialized LogWriter object. | |
func NewLogWriter(path string) *LogWriter { | |
w := &LogWriter{ | |
path: path, | |
logCh: make(chan string), | |
ctlCh: make(chan logWriterCtl), | |
closeResultCh: make(chan bool), | |
} | |
w.openFile() | |
return w | |
} | |
// Run a thread | |
func (w *LogWriter) Run() { | |
go w.loop() | |
} | |
// Reopen log file | |
func (w *LogWriter) Reopen() { | |
w.ctlCh <- reopenCtl | |
} | |
// Close log file and exit thread | |
func (w *LogWriter) Close() { | |
w.ctlCh <- closeCtl | |
<-w.closeResultCh | |
} | |
// Write a log | |
func (w *LogWriter) Write(log string) { | |
w.logCh <- log | |
} | |
func (w *LogWriter) loop() { | |
OuterLoop: | |
for { | |
select { | |
case log := <-w.logCh: | |
if w.file == nil { | |
panic("log file is not open yet") | |
} | |
if _, err := w.file.Write(append([]byte(log), '\n')); err != nil { | |
panic(err) | |
} | |
case ctl := <-w.ctlCh: | |
var err error | |
switch ctl { | |
case reopenCtl: | |
err = w.reopenFile() | |
case closeCtl: | |
err = w.file.Close() | |
break OuterLoop | |
} | |
if err != nil { | |
panic(err.Error()) | |
} | |
} | |
} | |
w.closeResultCh <- true | |
} | |
func (w *LogWriter) openFile() (err error) { | |
w.file, err = os.OpenFile(w.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) | |
return | |
} | |
func (w *LogWriter) reopenFile() (err error) { | |
oldFile := w.file | |
w.file, err = os.OpenFile(w.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) | |
oldFile.Close() | |
return | |
} |
package main | |
import ( | |
"fmt" | |
"time" | |
) | |
func main() { | |
writer := NewLogWriter("./test.txt") | |
for _, c := range []string{"A", "B", "C"} { | |
go func(c string) { | |
for i := 0; i < 1000; i++ { | |
writer.Write(fmt.Sprintf("%s: %d", c, i)) | |
time.Sleep(1000) | |
} | |
}(c) | |
} | |
writer.Run() | |
// sleep 1 000 000 000 | |
time.Sleep(1 * time.Second) | |
writer.Close() | |
} |