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  //}