github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/common/mclock/simclock.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 //版权所有2018 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 mclock 26 27 import ( 28 "sync" 29 "time" 30 ) 31 32 // 33 //在实际处理占用零时间的虚拟时间刻度上模拟调度程序。 34 // 35 //虚拟时钟本身不前进,调用run前进并执行计时器。 36 //由于无法影响Go调度程序,因此测试涉及的超时行为 37 //戈罗蒂内斯需要特别照顾。测试这种超时的一个好方法是:首先 38 //执行应该超时的操作。确保要测试的计时器 39 //创建。然后运行时钟直到超时之后。最后观察 40 //使用通道或信号量的超时。 41 type Simulated struct { 42 now AbsTime 43 scheduled []event 44 mu sync.RWMutex 45 cond *sync.Cond 46 } 47 48 type event struct { 49 do func() 50 at AbsTime 51 } 52 53 //RUN按给定的持续时间移动时钟,在该持续时间之前执行所有计时器。 54 func (s *Simulated) Run(d time.Duration) { 55 s.mu.Lock() 56 defer s.mu.Unlock() 57 s.init() 58 59 end := s.now + AbsTime(d) 60 for len(s.scheduled) > 0 { 61 ev := s.scheduled[0] 62 if ev.at > end { 63 break 64 } 65 s.now = ev.at 66 ev.do() 67 s.scheduled = s.scheduled[1:] 68 } 69 s.now = end 70 } 71 72 func (s *Simulated) ActiveTimers() int { 73 s.mu.RLock() 74 defer s.mu.RUnlock() 75 76 return len(s.scheduled) 77 } 78 79 func (s *Simulated) WaitForTimers(n int) { 80 s.mu.Lock() 81 defer s.mu.Unlock() 82 s.init() 83 84 for len(s.scheduled) < n { 85 s.cond.Wait() 86 } 87 } 88 89 //现在实现时钟。 90 func (s *Simulated) Now() AbsTime { 91 s.mu.RLock() 92 defer s.mu.RUnlock() 93 94 return s.now 95 } 96 97 //睡眠实现时钟。 98 func (s *Simulated) Sleep(d time.Duration) { 99 <-s.After(d) 100 } 101 102 //在执行时钟之后。 103 func (s *Simulated) After(d time.Duration) <-chan time.Time { 104 after := make(chan time.Time, 1) 105 s.insert(d, func() { 106 after <- (time.Time{}).Add(time.Duration(s.now)) 107 }) 108 return after 109 } 110 111 func (s *Simulated) insert(d time.Duration, do func()) { 112 s.mu.Lock() 113 defer s.mu.Unlock() 114 s.init() 115 116 at := s.now + AbsTime(d) 117 l, h := 0, len(s.scheduled) 118 ll := h 119 for l != h { 120 m := (l + h) / 2 121 if at < s.scheduled[m].at { 122 h = m 123 } else { 124 l = m + 1 125 } 126 } 127 s.scheduled = append(s.scheduled, event{}) 128 copy(s.scheduled[l+1:], s.scheduled[l:ll]) 129 s.scheduled[l] = event{do: do, at: at} 130 s.cond.Broadcast() 131 } 132 133 func (s *Simulated) init() { 134 if s.cond == nil { 135 s.cond = sync.NewCond(&s.mu) 136 } 137 }