From 8baf0b5619c5e903afa3997e87ff52d7bd108bf2 Mon Sep 17 00:00:00 2001 From: john Date: Thu, 25 Oct 2018 10:08:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9Bgtype.Set=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0Set=E5=8E=9F=E5=AD=90=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E8=BF=94=E5=9B=9E=E6=97=A7=E7=9A=84=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E5=80=BC=EF=BC=9B=E6=94=B9=E8=BF=9Bgcron=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84Cron=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=AF=B9=E8=B1=A1=EF=BC=8C=E5=A2=9E=E5=8A=A0New/Start?= =?UTF-8?q?/Stop=E6=96=B9=E6=B3=95=EF=BC=9BTODO++?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO | 3 + g/container/gtype/bool.go | 8 +- g/container/gtype/byte.go | 5 +- g/container/gtype/bytes.go | 7 +- g/container/gtype/float32.go | 4 +- g/container/gtype/float64.go | 4 +- g/container/gtype/int.go | 5 +- g/container/gtype/int32.go | 4 +- g/container/gtype/int64.go | 4 +- g/container/gtype/interface.go | 6 +- g/container/gtype/string.go | 4 +- g/container/gtype/uint.go | 4 +- g/container/gtype/uint32.go | 4 +- g/container/gtype/uint64.go | 4 +- g/os/gcron/gcron.go | 114 ++++++++++------------------ g/os/gcron/gcron_cron.go | 132 +++++++++++++++++++++++++++++++++ g/os/gcron/gcron_entry.go | 21 ++++++ geg/os/gcron/gcron.go | 16 ++-- geg/other/test.go | 8 +- 19 files changed, 244 insertions(+), 113 deletions(-) create mode 100644 g/os/gcron/gcron_cron.go create mode 100644 g/os/gcron/gcron_entry.go diff --git a/TODO b/TODO index 855988852..be58dc541 100644 --- a/TODO +++ b/TODO @@ -37,6 +37,9 @@ ghttp.Request增加对输入参数的自动HtmlEncode机制; Cookie设置中文失效问题; ghttp hook回调使用方式在注册路由比较多的时候,优先级可能使得开发者混乱,考虑方式便于管理; 使用gconv将slice映射到struct属性上,例如redis hscan的结果集; +项目参考: + https://github.com/namreg/godown + https://github.com/Masterminds/sprig diff --git a/g/container/gtype/bool.go b/g/container/gtype/bool.go index fc62e295d..42a47e824 100644 --- a/g/container/gtype/bool.go +++ b/g/container/gtype/bool.go @@ -30,12 +30,14 @@ func (t *Bool) Clone() *Bool { return NewBool(t.Val()) } -func (t *Bool) Set(value bool) { +// 并发安全设置变量值,返回之前的旧值 +func (t *Bool) Set(value bool) (old bool) { if value { - atomic.StoreInt32(&t.val, 1) + old = atomic.SwapInt32(&t.val, 1) == 1 } else { - atomic.StoreInt32(&t.val, 0) + old = atomic.SwapInt32(&t.val, 0) == 1 } + return } func (t *Bool) Val() bool { diff --git a/g/container/gtype/byte.go b/g/container/gtype/byte.go index 67adf91b1..a1b721272 100644 --- a/g/container/gtype/byte.go +++ b/g/container/gtype/byte.go @@ -25,8 +25,9 @@ func (t *Byte) Clone() *Byte { return NewByte(t.Val()) } -func (t *Byte) Set(value byte) { - atomic.StoreInt32(&t.val, int32(value)) +// 并发安全设置变量值,返回之前的旧值 +func (t *Byte) Set(value byte) (old byte) { + return byte(atomic.SwapInt32(&t.val, int32(value))) } func (t *Byte) Val() byte { diff --git a/g/container/gtype/bytes.go b/g/container/gtype/bytes.go index fb067de5d..3cbd6b552 100644 --- a/g/container/gtype/bytes.go +++ b/g/container/gtype/bytes.go @@ -24,13 +24,14 @@ func (t *Bytes) Clone() *Bytes { return NewBytes(t.Val()) } -func (t *Bytes) Set(value []byte) { +func (t *Bytes) Set(value []byte) (old []byte) { + old = t.Val() t.val.Store(value) + return } func (t *Bytes) Val() []byte { - s := t.val.Load() - if s != nil { + if s := t.val.Load(); s != nil { return s.([]byte) } return nil diff --git a/g/container/gtype/float32.go b/g/container/gtype/float32.go index 7e11339c8..dada43e64 100644 --- a/g/container/gtype/float32.go +++ b/g/container/gtype/float32.go @@ -26,8 +26,8 @@ func (t *Float32) Clone() *Float32 { return NewFloat32(t.Val()) } -func (t *Float32) Set(value float32) { - atomic.StoreUint32(&t.val, float32ToUint32InBits(value) ) +func (t *Float32) Set(value float32) (old float32) { + return uint32ToFloat32InBits(atomic.SwapUint32(&t.val, float32ToUint32InBits(value))) } func (t *Float32) Val() float32 { diff --git a/g/container/gtype/float64.go b/g/container/gtype/float64.go index 5f1bd100b..7de05311e 100644 --- a/g/container/gtype/float64.go +++ b/g/container/gtype/float64.go @@ -26,8 +26,8 @@ func (t *Float64) Clone() *Float64 { return NewFloat64(t.Val()) } -func (t *Float64) Set(value float64) { - atomic.StoreUint64(&t.val, float64ToUint64InBits(value) ) +func (t *Float64) Set(value float64) (old float64) { + return uint64ToFloat64InBits(atomic.SwapUint64(&t.val, float64ToUint64InBits(value))) } func (t *Float64) Val() float64 { diff --git a/g/container/gtype/int.go b/g/container/gtype/int.go index 2cc9ee751..92ee334c0 100644 --- a/g/container/gtype/int.go +++ b/g/container/gtype/int.go @@ -25,8 +25,9 @@ func (t *Int) Clone() *Int { return NewInt(t.Val()) } -func (t *Int) Set(value int) { - atomic.StoreInt64(&t.val, int64(value)) +// 并发安全设置变量值,返回之前的旧值 +func (t *Int) Set(value int) (old int) { + return int(atomic.SwapInt64(&t.val, int64(value))) } func (t *Int) Val() int { diff --git a/g/container/gtype/int32.go b/g/container/gtype/int32.go index 2234a22c0..ddfc2eff8 100644 --- a/g/container/gtype/int32.go +++ b/g/container/gtype/int32.go @@ -25,8 +25,8 @@ func (t *Int32) Clone() *Int32 { return NewInt32(t.Val()) } -func (t *Int32) Set(value int32) { - atomic.StoreInt32(&t.val, value) +func (t *Int32) Set(value int32) (old int32) { + return atomic.SwapInt32(&t.val, value) } func (t *Int32) Val() int32 { diff --git a/g/container/gtype/int64.go b/g/container/gtype/int64.go index 24d4cf579..c5543942e 100644 --- a/g/container/gtype/int64.go +++ b/g/container/gtype/int64.go @@ -25,8 +25,8 @@ func (t *Int64) Clone() *Int64 { return NewInt64(t.Val()) } -func (t *Int64) Set(value int64) { - atomic.StoreInt64(&t.val, value) +func (t *Int64) Set(value int64) (old int64) { + return atomic.SwapInt64(&t.val, value) } func (t *Int64) Val() int64 { diff --git a/g/container/gtype/interface.go b/g/container/gtype/interface.go index 35ec814a4..995407fb7 100644 --- a/g/container/gtype/interface.go +++ b/g/container/gtype/interface.go @@ -23,15 +23,17 @@ func NewInterface(value...interface{}) *Interface { return t } -func (t *Interface) Clone() *Interface{ +func (t *Interface) Clone() *Interface { return NewInterface(t.Val()) } -func (t *Interface) Set(value interface{}) { +func (t *Interface) Set(value interface{}) (old interface{}) { if value == nil { return } + old = t.Val() t.val.Store(value) + return } func (t *Interface) Val() interface{} { diff --git a/g/container/gtype/string.go b/g/container/gtype/string.go index ede15a093..9221f636f 100644 --- a/g/container/gtype/string.go +++ b/g/container/gtype/string.go @@ -26,8 +26,10 @@ func (t *String) Clone() *String { return NewString(t.Val()) } -func (t *String) Set(value string) { +func (t *String) Set(value string) (old string) { + old = t.Val() t.val.Store(value) + return } func (t *String) Val() string { diff --git a/g/container/gtype/uint.go b/g/container/gtype/uint.go index ff2710c0e..b2af0f5c0 100644 --- a/g/container/gtype/uint.go +++ b/g/container/gtype/uint.go @@ -25,8 +25,8 @@ func (t *Uint) Clone() *Uint { return NewUint(t.Val()) } -func (t *Uint) Set(value uint) { - atomic.StoreUint64(&t.val, uint64(value)) +func (t *Uint) Set(value uint) (old uint) { + return uint(atomic.SwapUint64(&t.val, uint64(value))) } func (t *Uint) Val() uint { diff --git a/g/container/gtype/uint32.go b/g/container/gtype/uint32.go index 57976d2d3..7cb2da5c2 100644 --- a/g/container/gtype/uint32.go +++ b/g/container/gtype/uint32.go @@ -25,8 +25,8 @@ func (t *Uint32) Clone() *Uint32 { return NewUint32(t.Val()) } -func (t *Uint32) Set(value uint32) { - atomic.StoreUint32(&t.val, value) +func (t *Uint32) Set(value uint32) (old uint32) { + return atomic.SwapUint32(&t.val, value) } func (t *Uint32) Val() uint32 { diff --git a/g/container/gtype/uint64.go b/g/container/gtype/uint64.go index faf21e22c..ea8ba1431 100644 --- a/g/container/gtype/uint64.go +++ b/g/container/gtype/uint64.go @@ -25,8 +25,8 @@ func (t *Uint64) Clone() *Uint64 { return NewUint64(t.Val()) } -func (t *Uint64) Set(value uint64) { - atomic.StoreUint64(&t.val, value) +func (t *Uint64) Set(value uint64) (old uint64) { + return atomic.SwapUint64(&t.val, value) } func (t *Uint64) Val() uint64 { diff --git a/g/os/gcron/gcron.go b/g/os/gcron/gcron.go index df57f653a..ef61dfd2e 100644 --- a/g/os/gcron/gcron.go +++ b/g/os/gcron/gcron.go @@ -8,107 +8,69 @@ package gcron import ( - "errors" - "fmt" "gitee.com/johng/gf/g/container/garray" "gitee.com/johng/gf/g/container/gtype" "gitee.com/johng/gf/g/os/gtime" "gitee.com/johng/gf/third/github.com/robfig/cron" - "reflect" - "runtime" ) // 定时任务项 type Entry struct { - Spec string // 注册定时任务时间格式 - Cmd string // 注册定时任务名称 - Time *gtime.Time // 注册时间 - Name string // 定时任务名称 - cron *cron.Cron // 底层定时管理对象 + Spec string // 注册定时任务时间格式 + Cmd string // 注册定时任务名称 + Time *gtime.Time // 注册时间 + Name string // 定时任务名称 + Status *gtype.Int // 定时任务状态(0: 未执行; > 0: 运行中) + cron *cron.Cron // 定时任务单独的底层定时管理对象 +} + +// 定时任务管理对象 +type Cron struct { + cron *cron.Cron // 底层定时管理对象 + entries *garray.Array // 定时任务注册项 + status *gtype.Int // 默认定时任务管理对象状态(不带名称的定时任务,0: 未执行; > 0: 运行中) } var ( // 默认的cron管理对象 - defaultCron = cron.New() - // 当前cron的运行状态(0: 未执行; > 0: 运行中) - cronStatus = gtype.NewInt() - // 注册定时任务项 - cronEntries = garray.New(0, 0, true) + defaultCron = New() ) +// 创建自定义的定时任务管理对象 +func New() *Cron { + return &Cron { + cron : cron.New(), + entries : garray.New(0, 0, true), + status : gtype.NewInt(), + } +} + // 添加执行方法,可以给定名字,以便于后续执行删除 func Add(spec string, f func(), name ... string) error { - if len(name) > 0 { - if Search(name[0]) != nil { - return errors.New(fmt.Sprintf(`cron job "%s" already exists`, name[0])) - } - c := cron.New() - if err := c.AddFunc(spec, f); err == nil { - cronEntries.Append(Entry{ - Spec : spec, - Cmd : runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name(), - Time : gtime.Now(), - Name : name[0], - cron : c, - }) - go c.Run() - } else { - return err - } - } else { - if err := defaultCron.AddFunc(spec, f); err == nil { - if cronStatus.Add(1) == 1 { - go defaultCron.Run() - } - cronEntries.Append(Entry{ - Spec : spec, - Cmd : runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name(), - Time : gtime.Now(), - }) - } else { - return err - } - } - return nil + return defaultCron.Add(spec, f, name...) } // 检索指定名称的定时任务 func Search(name string) *Entry { - entry, _ := searchEntry(name) - return entry -} - -// 检索指定名称的定时任务 -func searchEntry(name string) (*Entry, int) { - entry := (*Entry)(nil) - index := -1 - cronEntries.RLockFunc(func(array []interface{}) { - for k, v := range array { - e := v.(Entry) - if e.Name == name { - entry = &e - index = k - break - } - } - }) - return entry, index + return defaultCron.Search(name) } // 根据指定名称删除定时任务 func Remove(name string) { - if entry, index := searchEntry(name); index >= 0 { - entry.cron.Stop() - cronEntries.Remove(index) - } + defaultCron.Remove(name) } // 获取所有已注册的定时任务项 -func Entries() []Entry { - length := cronEntries.Len() - entries := make([]Entry, length) - for i := 0; i < length; i++ { - entries[i] = cronEntries.Get(i).(Entry) - } - return entries +func Entries() []*Entry { + return defaultCron.Entries() +} + +// 启动指定的定时任务 +func Start(name string) { + defaultCron.Start(name) +} + +// 停止指定的定时任务 +func Stop(name string) { + defaultCron.Stop(name) } diff --git a/g/os/gcron/gcron_cron.go b/g/os/gcron/gcron_cron.go new file mode 100644 index 000000000..96c5ef175 --- /dev/null +++ b/g/os/gcron/gcron_cron.go @@ -0,0 +1,132 @@ +// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://gitee.com/johng/gf. + +package gcron + +import ( + "errors" + "fmt" + "gitee.com/johng/gf/g/container/gtype" + "gitee.com/johng/gf/g/os/gtime" + "gitee.com/johng/gf/third/github.com/robfig/cron" + "reflect" + "runtime" +) + +// 添加定时任务 +func (c *Cron) Add(spec string, f func(), name ... string) error { + if len(name) > 0 { + if Search(name[0]) != nil { + return errors.New(fmt.Sprintf(`cron job "%s" already exists`, name[0])) + } + jobCron := cron.New() + if err := jobCron.AddFunc(spec, f); err == nil { + entry := &Entry{ + Spec : spec, + Cmd : runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name(), + Time : gtime.Now(), + Name : name[0], + Status : gtype.NewInt(0), + cron : jobCron, + } + entry.Start() + c.entries.Append(entry) + } else { + return err + } + } else { + if err := c.cron.AddFunc(spec, f); err == nil { + entry := &Entry{ + Spec : spec, + Cmd : runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name(), + Time : gtime.Now(), + Status : c.status, + cron : c.cron, + } + entry.Start() + c.entries.Append(entry) + } else { + return err + } + } + return nil +} + +// 检索指定名称的定时任务 +func (c *Cron) Search(name string) *Entry { + entry, _ := c.searchEntry(name) + return entry +} + +// 检索指定名称的定时任务 +func (c *Cron) searchEntry(name string) (*Entry, int) { + entry := (*Entry)(nil) + index := -1 + c.entries.RLockFunc(func(array []interface{}) { + for k, v := range array { + e := v.(*Entry) + if e.Name == name { + entry = e + index = k + break + } + } + }) + return entry, index +} + +// 根据指定名称删除定时任务 +func (c *Cron) Remove(name string) { + if entry, index := c.searchEntry(name); index >= 0 { + entry.cron.Stop() + c.entries.Remove(index) + } +} + +// 开启定时任务执行(可以指定特定名称的一个或若干个定时任务) +func (c *Cron) Start(name...string) { + if len(name) > 0 { + for _, v := range name { + if entry := c.Search(v); entry != nil { + entry.Start() + } + } + } else { + c.entries.RLockFunc(func(array []interface{}) { + for _, v := range array { + v.(*Entry).Start() + } + }) + } +} + +// 关闭定时任务执行(可以指定特定名称的一个或若干个定时任务) +func (c *Cron) Stop(name...string) { + if len(name) > 0 { + for _, v := range name { + if entry := c.Search(v); entry != nil { + entry.Stop() + } + } + } else { + c.entries.RLockFunc(func(array []interface{}) { + for _, v := range array { + v.(*Entry).Stop() + } + }) + } +} + + +// 获取所有已注册的定时任务项 +func (c *Cron) Entries() []*Entry { + length := c.entries.Len() + entries := make([]*Entry, length) + for i := 0; i < length; i++ { + entries[i] = c.entries.Get(i).(*Entry) + } + return entries +} diff --git a/g/os/gcron/gcron_entry.go b/g/os/gcron/gcron_entry.go new file mode 100644 index 000000000..9bf55cfc9 --- /dev/null +++ b/g/os/gcron/gcron_entry.go @@ -0,0 +1,21 @@ +// Copyright 2018 gf Author(https://gitee.com/johng/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://gitee.com/johng/gf. + +package gcron + +// 启动定时任务 +func (entry *Entry) Start() { + if entry.Status.Set(1) == 0 { + entry.cron.Start() + } +} + +// 关闭定时任务 +func (entry *Entry) Stop() { + if entry.Status.Set(0) == 1 { + entry.cron.Stop() + } +} diff --git a/geg/os/gcron/gcron.go b/geg/os/gcron/gcron.go index 5f2ab5c42..5ce3f1e69 100644 --- a/geg/os/gcron/gcron.go +++ b/geg/os/gcron/gcron.go @@ -1,22 +1,26 @@ package main import ( - "fmt" "gitee.com/johng/gf/g" "gitee.com/johng/gf/g/os/gcron" + "gitee.com/johng/gf/g/os/glog" "time" ) func main() { - gcron.Add("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") }) - gcron.Add("* * * * * *", func() { fmt.Println("Every second") }, "second-cron") - gcron.Add("@hourly", func() { fmt.Println("Every hour") }) - gcron.Add("@every 1h30m", func() { fmt.Println("Every hour thirty") }) + gcron.Add("0 30 * * * *", func() { glog.Println("Every hour on the half hour") }) + gcron.Add("* * * * * *", func() { glog.Println("Every second") }, "second-cron") + gcron.Add("@hourly", func() { glog.Println("Every hour") }) + gcron.Add("@every 1h30m", func() { glog.Println("Every hour thirty") }) g.Dump(gcron.Entries()) time.Sleep(3*time.Second) - gcron.Remove("second-cron") + gcron.Stop("second-cron") + + time.Sleep(3*time.Second) + + gcron.Start("second-cron") time.Sleep(3*time.Second) } \ No newline at end of file diff --git a/geg/other/test.go b/geg/other/test.go index fdce2bc06..8c43214c4 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "gitee.com/johng/gf/g/container/gvar" + "gitee.com/johng/gf/g/container/gtype" ) func test() { @@ -11,7 +11,7 @@ func test() { } func main() { - var v *gvar.Var - //v := new(gvar.Var) - fmt.Println(v.String()) + v := gtype.NewInt(1) + fmt.Println(v.Set(2)) + fmt.Println(v.Set(2)) }