github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/event/feed.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2016 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package event 26 27 import ( 28 "errors" 29 "reflect" 30 "sync" 31 ) 32 33 var errBadChannel = errors.New("event: Subscribe argument does not have sendable channel type") 34 35 //feed实现了一对多的订阅,其中事件的载体是一个通道。 36 //发送到提要的值将同时传递到所有订阅的通道。 37 // 38 //源只能与单个类型一起使用。类型由第一次发送或 39 //订阅操作。如果类型不为 40 //比赛。 41 // 42 //零值已准备好使用。 43 type Feed struct { 44 once sync.Once //确保init只运行一次 45 sendLock chan struct{} //sendlock有一个单元素缓冲区,保持时为空。它保护发送案例。 46 removeSub chan interface{} //中断发送 47 sendCases caseList //send使用的select cases的活动集 48 49 //收件箱保存新订阅的频道,直到它们被添加到发送案例中。 50 mu sync.Mutex 51 inbox caseList 52 etype reflect.Type 53 closed bool 54 } 55 56 //这是发送案例中第一个实际订阅通道的索引。 57 //sendcases[0]是removeSub通道的selectRecv案例。 58 const firstSubSendCase = 1 59 60 type feedTypeError struct { 61 got, want reflect.Type 62 op string 63 } 64 65 func (e feedTypeError) Error() string { 66 return "event: wrong type in " + e.op + " got " + e.got.String() + ", want " + e.want.String() 67 } 68 69 func (f *Feed) init() { 70 f.removeSub = make(chan interface{}) 71 f.sendLock = make(chan struct{}, 1) 72 f.sendLock <- struct{}{} 73 f.sendCases = caseList{{Chan: reflect.ValueOf(f.removeSub), Dir: reflect.SelectRecv}} 74 } 75 76 //订阅向订阅源添加一个频道。未来的发送将在通道上传递 77 //直到取消订阅。添加的所有通道必须具有相同的元素类型。 78 // 79 //通道应该有足够的缓冲空间,以避免阻塞其他订户。 80 //不会删除速度较慢的订阅服务器。 81 func (f *Feed) Subscribe(channel interface{}) Subscription { 82 f.once.Do(f.init) 83 84 chanval := reflect.ValueOf(channel) 85 chantyp := chanval.Type() 86 if chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.SendDir == 0 { 87 panic(errBadChannel) 88 } 89 sub := &feedSub{feed: f, channel: chanval, err: make(chan error, 1)} 90 91 f.mu.Lock() 92 defer f.mu.Unlock() 93 if !f.typecheck(chantyp.Elem()) { 94 panic(feedTypeError{op: "Subscribe", got: chantyp, want: reflect.ChanOf(reflect.SendDir, f.etype)}) 95 } 96 //将选择案例添加到收件箱。 97 //下一次发送将把它添加到f.sendcases。 98 cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval} 99 f.inbox = append(f.inbox, cas) 100 return sub 101 } 102 103 //注:呼叫者必须持有F.MU 104 func (f *Feed) typecheck(typ reflect.Type) bool { 105 if f.etype == nil { 106 f.etype = typ 107 return true 108 } 109 return f.etype == typ 110 } 111 112 func (f *Feed) remove(sub *feedSub) { 113 //首先从收件箱中删除,包括频道 114 //尚未添加到f.sendcases。 115 ch := sub.channel.Interface() 116 f.mu.Lock() 117 index := f.inbox.find(ch) 118 if index != -1 { 119 f.inbox = f.inbox.delete(index) 120 f.mu.Unlock() 121 return 122 } 123 f.mu.Unlock() 124 125 select { 126 case f.removeSub <- ch: 127 //send将从f.sendscases中删除通道。 128 case <-f.sendLock: 129 //没有发送正在进行中,请删除该频道,因为我们有发送锁。 130 f.sendCases = f.sendCases.delete(f.sendCases.find(ch)) 131 f.sendLock <- struct{}{} 132 } 133 } 134 135 //发送同时发送到所有订阅的频道。 136 //它返回值发送到的订户数。 137 func (f *Feed) Send(value interface{}) (nsent int) { 138 rvalue := reflect.ValueOf(value) 139 140 f.once.Do(f.init) 141 <-f.sendLock 142 143 //获取发送锁定后从收件箱添加新案例。 144 f.mu.Lock() 145 f.sendCases = append(f.sendCases, f.inbox...) 146 f.inbox = nil 147 148 if !f.typecheck(rvalue.Type()) { 149 f.sendLock <- struct{}{} 150 panic(feedTypeError{op: "Send", got: rvalue.Type(), want: f.etype}) 151 } 152 f.mu.Unlock() 153 154 //在所有通道上设置发送值。 155 for i := firstSubSendCase; i < len(f.sendCases); i++ { 156 f.sendCases[i].Send = rvalue 157 } 158 159 //发送,直到选择了除removesub以外的所有频道。cases'跟踪前缀 160 //病例报告。当发送成功时,相应的事例将移动到 161 //“cases”和它收缩一个元素。 162 cases := f.sendCases 163 for { 164 //快速路径:在添加到选择集之前,尝试不阻塞地发送。 165 //如果订户速度足够快并且有免费服务,这通常会成功。 166 //缓冲空间。 167 for i := firstSubSendCase; i < len(cases); i++ { 168 if cases[i].Chan.TrySend(rvalue) { 169 nsent++ 170 cases = cases.deactivate(i) 171 i-- 172 } 173 } 174 if len(cases) == firstSubSendCase { 175 break 176 } 177 //选择所有接收器,等待其解锁。 178 chosen, recv, _ := reflect.Select(cases) 179 /*已选择==0/*<-f.removesub*/ 180 索引:=f.sendcases.find(recv.interface()) 181 F.sEdvase= f.sEndeStask.删除(索引) 182 如果index>=0&&index<len(cases) 183 //也收缩“cases”,因为删除的case仍处于活动状态。 184 cases=f.sendcases[:len(cases)-1] 185 } 186 }否则{ 187 cases=cases.deactivate(已选择) 188 nt++ 189 } 190 } 191 192 //忽略发送值,并关闭发送锁。 193 对于i:=firstsubsendcase;i<len(f.sendcases);i++ 194 f.sendcases[i].send=reflect.value 195 } 196 f.sendlock<-结构 197 返回N发送 198 } 199 200 类型FEEDSUB结构 201 进料*进料 202 通道反射值 203 误差同步一次 204 错误通道错误 205 } 206 207 func(sub*feedsub)unsubscribe() 208 sub.erronce.do(func() 209 sub.feed.移除(sub) 210 关闭(子) 211 }) 212 } 213 214 func(sub*feedsub)err()<-chan错误 215 返回错误 216 } 217 218 键入caselist[]reflect.selectcase 219 220 //find返回包含给定通道的事例的索引。 221 func(cs caselist)find(通道接口)int 222 对于I,CAS:=范围CS { 223 如果Cas.Chan.IdFACEL()=通道{ 224 返回我 225 } 226 } 227 返回- 1 228 } 229 230 //删除从cs中删除给定的case。 231 func(cs caselist)删除(index int)caselist_ 232 返回附加(cs[:index],cs[index+1:…) 233 } 234 235 //deactivate将索引处的大小写移动到cs切片的不可访问部分。 236 func(cs caselist)deactivate(index int)caselist_ 237 最后:=len(cs)-1 238 cs[索引],cs[最后]=cs[最后],cs[索引] 239 返回cs[:last] 240 } 241 242 //func(cs caselist)string()字符串 243 //s:=“” 244 //对于i,cas:=范围cs 245 //如果我!= 0 { 246 //s+=“,” 247 // 248 //切换cas.dir 249 //case reflect.selectsend: 250 //s+=fmt.sprintf(“%v<-”,cas.chan.interface()) 251 //case reflect.selectrecv: 252 //s+=fmt.sprintf(“<-%v”,cas.chan.interface()) 253 // 254 //} 255 //返回s+“]” 256 //}