github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/event/feed.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:38</date> 10 //</624450091054272512> 11 12 13 package event 14 15 import ( 16 "errors" 17 "reflect" 18 "sync" 19 ) 20 21 var errBadChannel = errors.New("event: Subscribe argument does not have sendable channel type") 22 23 //feed实现了一对多的订阅,其中事件的载体是一个通道。 24 //发送到提要的值将同时传递到所有订阅的通道。 25 // 26 //源只能与单个类型一起使用。类型由第一次发送或 27 //订阅操作。如果类型不为 28 //比赛。 29 // 30 //零值已准备好使用。 31 type Feed struct { 32 once sync.Once //确保init只运行一次 33 sendLock chan struct{} //sendlock有一个单元素缓冲区,保持时为空。它保护发送案例。 34 removeSub chan interface{} //中断发送 35 sendCases caseList //the active set of select cases used by Send 36 37 //收件箱保存新订阅的频道,直到它们被添加到发送案例中。 38 mu sync.Mutex 39 inbox caseList 40 etype reflect.Type 41 closed bool 42 } 43 44 //这是发送案例中第一个实际订阅通道的索引。 45 //sendCases[0] is a SelectRecv case for the removeSub channel. 46 const firstSubSendCase = 1 47 48 type feedTypeError struct { 49 got, want reflect.Type 50 op string 51 } 52 53 func (e feedTypeError) Error() string { 54 return "event: wrong type in " + e.op + " got " + e.got.String() + ", want " + e.want.String() 55 } 56 57 func (f *Feed) init() { 58 f.removeSub = make(chan interface{}) 59 f.sendLock = make(chan struct{}, 1) 60 f.sendLock <- struct{}{} 61 f.sendCases = caseList{{Chan: reflect.ValueOf(f.removeSub), Dir: reflect.SelectRecv}} 62 } 63 64 //订阅向订阅源添加一个频道。未来的发送将在通道上传递 65 //直到取消订阅。添加的所有通道必须具有相同的元素类型。 66 // 67 //通道应该有足够的缓冲空间,以避免阻塞其他订户。 68 //不会删除速度较慢的订阅服务器。 69 func (f *Feed) Subscribe(channel interface{}) Subscription { 70 f.once.Do(f.init) 71 72 chanval := reflect.ValueOf(channel) 73 chantyp := chanval.Type() 74 if chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.SendDir == 0 { 75 panic(errBadChannel) 76 } 77 sub := &feedSub{feed: f, channel: chanval, err: make(chan error, 1)} 78 79 f.mu.Lock() 80 defer f.mu.Unlock() 81 if !f.typecheck(chantyp.Elem()) { 82 panic(feedTypeError{op: "Subscribe", got: chantyp, want: reflect.ChanOf(reflect.SendDir, f.etype)}) 83 } 84 //Add the select case to the inbox. 85 //下一次发送将把它添加到f.sendcases。 86 cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval} 87 f.inbox = append(f.inbox, cas) 88 return sub 89 } 90 91 //注:呼叫者必须持有F.MU 92 func (f *Feed) typecheck(typ reflect.Type) bool { 93 if f.etype == nil { 94 f.etype = typ 95 return true 96 } 97 return f.etype == typ 98 } 99 100 func (f *Feed) remove(sub *feedSub) { 101 //Delete from inbox first, which covers channels 102 //尚未添加到f.sendcases。 103 ch := sub.channel.Interface() 104 f.mu.Lock() 105 index := f.inbox.find(ch) 106 if index != -1 { 107 f.inbox = f.inbox.delete(index) 108 f.mu.Unlock() 109 return 110 } 111 f.mu.Unlock() 112 113 select { 114 case f.removeSub <- ch: 115 //send将从f.sendscases中删除通道。 116 case <-f.sendLock: 117 //No Send is in progress, delete the channel now that we have the send lock. 118 f.sendCases = f.sendCases.delete(f.sendCases.find(ch)) 119 f.sendLock <- struct{}{} 120 } 121 } 122 123 //发送同时发送到所有订阅的频道。 124 //它返回值发送到的订户数。 125 func (f *Feed) Send(value interface{}) (nsent int) { 126 rvalue := reflect.ValueOf(value) 127 128 f.once.Do(f.init) 129 <-f.sendLock 130 131 //获取发送锁定后从收件箱添加新案例。 132 f.mu.Lock() 133 f.sendCases = append(f.sendCases, f.inbox...) 134 f.inbox = nil 135 136 if !f.typecheck(rvalue.Type()) { 137 f.sendLock <- struct{}{} 138 panic(feedTypeError{op: "Send", got: rvalue.Type(), want: f.etype}) 139 } 140 f.mu.Unlock() 141 142 //在所有通道上设置发送值。 143 for i := firstSubSendCase; i < len(f.sendCases); i++ { 144 f.sendCases[i].Send = rvalue 145 } 146 147 //发送,直到选择了除removesub以外的所有频道。cases'跟踪前缀 148 //病例报告。当发送成功时,相应的事例将移动到 149 //“cases”和它收缩一个元素。 150 cases := f.sendCases 151 for { 152 //快速路径:在添加到选择集之前,尝试不阻塞地发送。 153 //如果订户速度足够快并且有免费服务,这通常会成功。 154 //缓冲空间。 155 for i := firstSubSendCase; i < len(cases); i++ { 156 if cases[i].Chan.TrySend(rvalue) { 157 nsent++ 158 cases = cases.deactivate(i) 159 i-- 160 } 161 } 162 if len(cases) == firstSubSendCase { 163 break 164 } 165 //选择所有接收器,等待其解锁。 166 chosen, recv, _ := reflect.Select(cases) 167 /*已选择==0/*<-f.removesub*/ 168 索引:=f.sendcases.find(recv.interface()) 169 F.sEdvase= f.sEndeStask.删除(索引) 170 如果index>=0&&index<len(cases) 171 // Shrink 'cases' too because the removed case was still active. 172 cases=f.sendcases[:len(cases)-1] 173 } 174 }否则{ 175 cases = cases.deactivate(chosen) 176 nt++ 177 } 178 } 179 180 //忽略发送值,并关闭发送锁。 181 对于i:=firstsubsendcase;i<len(f.sendcases);i++ 182 f.sendcases[i].send=reflect.value 183 } 184 f.sendlock<-结构 185 返回N发送 186 } 187 188 类型FEEDSUB结构 189 进料*进料 190 通道反射值 191 误差同步一次 192 错误通道错误 193 } 194 195 func(sub*feedsub)unsubscribe() 196 sub.errOnce.Do(func() { 197 sub.feed.移除(sub) 198 关闭(子) 199 }) 200 } 201 202 func(sub*feedsub)err()<-chan错误 203 返回错误 204 } 205 206 键入caselist[]reflect.selectcase 207 208 //find返回包含给定通道的事例的索引。 209 func(cs caselist)find(通道接口)int 210 对于I,CAS:=范围CS { 211 如果Cas.Chan.IdFACEL()=通道{ 212 返回我 213 } 214 } 215 返回- 1 216 } 217 218 //删除从cs中删除给定的case。 219 func(cs caselist)删除(index int)caselist_ 220 返回附加(cs[:index],cs[index+1:…) 221 } 222 223 //deactivate将索引处的大小写移动到cs切片的不可访问部分。 224 func(cs caselist)deactivate(index int)caselist_ 225 最后:=len(cs)-1 226 cs[索引],cs[最后]=cs[最后],cs[索引] 227 返回cs[:last] 228 } 229 230 //func(cs caselist)string()字符串 231 //s:=“” 232 //对于i,cas:=范围cs 233 //如果我!= 0 { 234 //s+=“,” 235 // 236 //切换cas.dir 237 //case reflect.selectsend: 238 //s+=fmt.sprintf(“%v<-”,cas.chan.interface()) 239 //case reflect.selectrecv: 240 //s+=fmt.sprintf(“<-%v”,cas.chan.interface()) 241 // 242 //} 243 //返回s+“]” 244 //} 245