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