github.com/loov/combiner@v0.1.0/example/append.go (about) 1 // +build ignore 2 3 package main 4 5 import ( 6 "fmt" 7 "os" 8 "runtime" 9 "sync" 10 "time" 11 12 "github.com/loov/combiner" 13 "github.com/loov/hrtime" 14 ) 15 16 const ( 17 P = 100 18 N = 100 19 ) 20 21 func main() { 22 f, _ := os.Create("temp.dat~") 23 f.Truncate(P * N) 24 25 f.Seek(0, os.SEEK_SET) 26 fmt.Println("CombiningFile", Bench(NewCombiningFile(f))) 27 28 cfile := NewChanFile(f) 29 cfile.Start() 30 f.Seek(0, os.SEEK_SET) 31 fmt.Println("ChanFile", Bench(cfile)) 32 cfile.Stop() 33 34 f.Seek(0, os.SEEK_SET) 35 fmt.Println("MutexFile", Bench(NewMutexFile(f))) 36 37 // Output: 38 // CombiningFile 161.179503ms 39 // ChanFile 220.223679ms 40 // MutexFile 10.987153817s 41 } 42 43 type Writer interface { 44 WriteByte(byte byte) 45 } 46 47 func Bench(w Writer) time.Duration { 48 start := hrtime.TSC() 49 50 var wg sync.WaitGroup 51 wg.Add(P) 52 for i := 0; i < P; i++ { 53 go func(pid int) { 54 for i := 0; i < N; i++ { 55 w.WriteByte(byte(i)) 56 } 57 wg.Done() 58 }(i) 59 } 60 wg.Wait() 61 62 stop := hrtime.TSC() 63 return (stop - start).ApproxDuration() 64 } 65 66 type CombiningFile struct { 67 add combiner.Parking 68 file *os.File 69 } 70 type combiningAppend CombiningFile 71 72 func NewCombiningFile(f *os.File) *CombiningFile { 73 m := &CombiningFile{} 74 m.add.Init((*combiningAppend)(m), 100) 75 m.file = f 76 return m 77 } 78 79 func (m *CombiningFile) WriteByte(b byte) { m.add.Do(b) } 80 81 func (m *combiningAppend) Start() { runtime.Gosched() } 82 func (m *combiningAppend) Do(arg interface{}) { m.file.Write([]byte{arg.(byte)}) } 83 func (m *combiningAppend) Finish() { m.file.Sync() } 84 85 type MutexFile struct { 86 mu sync.Mutex 87 file *os.File 88 } 89 90 func NewMutexFile(f *os.File) *MutexFile { 91 m := &MutexFile{} 92 m.file = f 93 return m 94 } 95 96 func (m *MutexFile) WriteByte(b byte) { 97 m.mu.Lock() 98 m.file.Write([]byte{b}) 99 m.file.Sync() 100 m.mu.Unlock() 101 } 102 103 type ChanFile struct { 104 req chan request 105 file *os.File 106 } 107 108 type request struct { 109 v byte 110 done chan struct{} 111 } 112 113 func NewChanFile(f *os.File) *ChanFile { 114 m := &ChanFile{} 115 m.req = make(chan request, 100) 116 m.file = f 117 return m 118 } 119 120 func (m *ChanFile) WriteByte(b byte) { 121 r := request{b, make(chan struct{}, 0)} 122 m.req <- r 123 <-r.done 124 } 125 126 func (m *ChanFile) Start() { 127 go func() { 128 var requests = []request{} 129 for { 130 requests = requests[:0] 131 132 r, ok := <-m.req 133 if !ok { 134 return 135 } 136 137 requests = append(requests, r) 138 m.file.Write([]byte{r.v}) 139 140 combining: 141 for count := 1; count < 100; count++ { 142 select { 143 case r, ok := <-m.req: 144 if !ok { 145 break combining 146 } 147 148 requests = append(requests, r) 149 m.file.Write([]byte{r.v}) 150 default: 151 break combining 152 } 153 } 154 155 m.file.Sync() 156 for _, req := range requests { 157 close(req.done) 158 } 159 } 160 }() 161 } 162 163 func (m *ChanFile) Stop() { close(m.req) }