Commit 87d86691 authored by fangyincheng's avatar fangyincheng

Add:add wheel

parents
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.idea
*.iml
target/
classes
# vim
*.swp
# go mod
go.mod
go.sum
// Copyright 2016 ~ 2018 AlexStocks(https://github.com/AlexStocks).
// All rights reserved. Use of this source code is
// governed by Apache License 2.0.
// Package gxtime encapsulates some golang.time functions
package gxtime
import (
"time"
)
/////////////////////////////////////////
// count watch
/////////////////////////////////////////
type CountWatch struct {
start time.Time
}
func (w *CountWatch) Start() {
var t time.Time
if t.Equal(w.start) {
w.start = time.Now()
}
}
func (w *CountWatch) Reset() {
w.start = time.Now()
}
func (w *CountWatch) Count() int64 {
return time.Since(w.start).Nanoseconds()
}
// Copyright 2016 ~ 2018 AlexStocks(https://github.com/AlexStocks).
// All rights reserved. Use of this source code is
// governed by Apache License 2.0.
// Package gxtime encapsulates some golang.time functions
package gxtime
import (
"strconv"
"time"
)
func TimeDayDuratioin(day float64) time.Duration {
return time.Duration(day * 24 * float64(time.Hour))
}
func TimeHourDuratioin(hour float64) time.Duration {
return time.Duration(hour * float64(time.Hour))
}
func TimeMinuteDuration(minute float64) time.Duration {
return time.Duration(minute * float64(time.Minute))
}
func TimeSecondDuration(sec float64) time.Duration {
return time.Duration(sec * float64(time.Second))
}
func TimeMillisecondDuration(m float64) time.Duration {
return time.Duration(m * float64(time.Millisecond))
}
func TimeMicrosecondDuration(m float64) time.Duration {
return time.Duration(m * float64(time.Microsecond))
}
func TimeNanosecondDuration(n float64) time.Duration {
return time.Duration(n * float64(time.Nanosecond))
}
// desc: convert year-month-day-hour-minute-seccond to int in second
// @month: 1 ~ 12
// @hour: 0 ~ 23
// @minute: 0 ~ 59
func YMD(year int, month int, day int, hour int, minute int, sec int) int {
return int(time.Date(year, time.Month(month), day, hour, minute, sec, 0, time.Local).Unix())
}
// @YMD in UTC timezone
func YMDUTC(year int, month int, day int, hour int, minute int, sec int) int {
return int(time.Date(year, time.Month(month), day, hour, minute, sec, 0, time.UTC).Unix())
}
func YMDPrint(sec int, nsec int) string {
return time.Unix(int64(sec), int64(nsec)).Format("2006-01-02 15:04:05.99999")
}
func Future(sec int, f func()) {
time.AfterFunc(TimeSecondDuration(float64(sec)), f)
}
func Unix2Time(unix int64) time.Time {
return time.Unix(unix, 0)
}
func UnixNano2Time(nano int64) time.Time {
return time.Unix(nano/1e9, nano%1e9)
}
func UnixString2Time(unix string) time.Time {
i, err := strconv.ParseInt(unix, 10, 64)
if err != nil {
panic(err)
}
return time.Unix(i, 0)
}
// 注意把time转换成unix的时候有精度损失,只返回了秒值,没有用到纳秒值
func Time2Unix(t time.Time) int64 {
return t.Unix()
}
func Time2UnixNano(t time.Time) int64 {
return t.UnixNano()
}
func GetEndtime(format string) time.Time {
timeNow := time.Now()
switch format {
case "day":
year, month, _ := timeNow.Date()
nextDay := timeNow.AddDate(0, 0, 1).Day()
t := time.Date(year, month, nextDay, 0, 0, 0, 0, time.Local)
return time.Unix(t.Unix()-1, 0)
case "week":
year, month, _ := timeNow.Date()
weekday := int(timeNow.Weekday())
weekendday := timeNow.AddDate(0, 0, 8-weekday).Day()
t := time.Date(year, month, weekendday, 0, 0, 0, 0, time.Local)
return time.Unix(t.Unix()-1, 0)
case "month":
year := timeNow.Year()
nextMonth := timeNow.AddDate(0, 1, 0).Month()
t := time.Date(year, nextMonth, 1, 0, 0, 0, 0, time.Local)
return time.Unix(t.Unix()-1, 0)
case "year":
nextYear := timeNow.AddDate(1, 0, 0).Year()
t := time.Date(nextYear, 1, 1, 0, 0, 0, 0, time.Local)
return time.Unix(t.Unix()-1, 0)
}
return timeNow
}
// Copyright 2016 ~ 2018 AlexStocks(https://github.com/AlexStocks).
// All rights reserved. Use of this source code is
// governed by Apache License 2.0.
// Package gxtime encapsulates some golang.time functions
// ref: https://github.com/AlexStocks/go-practice/blob/master/time/siddontang_time_wheel.go
package gxtime
import (
"sync"
"time"
)
type Wheel struct {
sync.RWMutex
span time.Duration
period time.Duration
ticker *time.Ticker
index int
ring []chan struct{}
once sync.Once
now time.Time
}
func NewWheel(span time.Duration, buckets int) *Wheel {
var (
w *Wheel
)
if span == 0 {
panic("@span == 0")
}
if buckets == 0 {
panic("@bucket == 0")
}
w = &Wheel{
span: span,
period: span * (time.Duration(buckets)),
ticker: time.NewTicker(span),
index: 0,
ring: make([](chan struct{}), buckets),
now: time.Now(),
}
go func() {
var notify chan struct{}
// var cw CountWatch
// cw.Start()
for t := range w.ticker.C {
w.Lock()
w.now = t
// fmt.Println("index:", w.index, ", value:", w.bitmap.Get(w.index))
notify = w.ring[w.index]
w.ring[w.index] = nil
w.index = (w.index + 1) % len(w.ring)
w.Unlock()
if notify != nil {
close(notify)
}
}
// fmt.Println("timer costs:", cw.Count()/1e9, "s")
}()
return w
}
func (w *Wheel) Stop() {
w.once.Do(func() { w.ticker.Stop() })
}
func (w *Wheel) After(timeout time.Duration) <-chan struct{} {
if timeout >= w.period {
panic("@timeout over ring's life period")
}
var pos = int(timeout / w.span)
if 0 < pos {
pos--
}
w.Lock()
pos = (w.index + pos) % len(w.ring)
if w.ring[pos] == nil {
w.ring[pos] = make(chan struct{})
}
// fmt.Println("pos:", pos)
c := w.ring[pos]
w.Unlock()
return c
}
func (w *Wheel) Now() time.Time {
w.RLock()
now := w.now
w.RUnlock()
return now
}
package gxtime
import (
"fmt"
"sync"
"testing"
"time"
)
// output:
// timer costs: 100002 ms
// --- PASS: TestNewWheel (100.00s)
func TestWheel(t *testing.T) {
var (
index int
wheel *Wheel
cw CountWatch
)
wheel = NewWheel(TimeMillisecondDuration(100), 20)
defer func() {
fmt.Println("timer costs:", cw.Count()/1e6, "ms")
wheel.Stop()
}()
cw.Start()
for {
select {
case <-wheel.After(TimeMillisecondDuration(1000)):
fmt.Println("loop:", index)
index++
if index >= 150 {
return
}
}
}
}
// output:
// timer costs: 150001 ms
// --- PASS: TestNewWheel2 (150.00s)
func TestWheels(t *testing.T) {
var (
wheel *Wheel
cw CountWatch
wg sync.WaitGroup
)
wheel = NewWheel(TimeMillisecondDuration(100), 20)
defer func() {
fmt.Println("timer costs:", cw.Count()/1e6, "ms") //
wheel.Stop()
}()
f := func(d time.Duration) {
defer wg.Done()
var index int
for {
select {
case <-wheel.After(d):
fmt.Println("loop:", index, ", interval:", d)
index++
if index >= 100 {
return
}
}
}
}
wg.Add(2)
cw.Start()
go f(1e9)
go f(1510e6)
wg.Wait()
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment