Skip to content

Instantly share code, notes, and snippets.

@harukasan
Last active August 29, 2015 14:22
Show Gist options
  • Save harukasan/5454fde35a1b657112b6 to your computer and use it in GitHub Desktop.
Save harukasan/5454fde35a1b657112b6 to your computer and use it in GitHub Desktop.
ログを書き込むスレッドをチャネル経由で制御する

ゴルーチンをつかってスレッドを作って非同期にするとき、そのスレッドをチャネル経由で制御するデモ。 気が向いたら説明を付加するけど、だいたいわかると思う。

Files

  • 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()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment