分享
  1. 首页
  2. 文章

在 Golang 定时任务中判断函数是否执行完成

nfwater · · 5019 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

使用 golang 的定时任务(采用 robfig/cron 包),每 5s 调用一个函数进行处理,但是这个函数的处理可能会耗时,在没有执行完之前如果再次调用,就会导致计算结果不对。

如定时任务:

// 5s 定时任务
func run5Second() {
	spec := "*/5, *, *, *, *, *"
	c := cron.New()
	//npc刷新
	c.AddFunc(spec, modelFish.NpcRefresh)
	c.Start()
}

NpcRefresh 方法定义:

// NpcRefresh 返回需要刷新的NPC
func NpcRefresh() {
	online := getOnlineRoomIds()
	//online := []string{"5"}
	fmt.Println("online room:", online)
	if len(online) > 0 {
		for _, roomID := range online {
			roomID, _ := strconv.Atoi(roomID)
			go doNpcRefresh(roomID)
		}
	}
}

这里 doNpcRefresh 方法起了多个 goroutine 去并发执行,里面有大量的计算,发现如果重复调用就会导致计算结果不正确,那么在每次的执行结束之前,不应该再次执行。

一开始想用 sync.waitGroup 的方式去同步,它的原理是把要执行的 goroutine 放队列,执行完出队列,队列没有完成前阻塞。这是一个方法,这样确实可以达到不重复执行一个未完成函数的目的,但是不适用当前的场景。

sync.waitGroup 用法示例:

package main
 
import (
 "fmt"
 "sync"
)
 
func main() {
 var wg sync.WaitGroup
 for i := 0; i < 100; i++ {
 wg.Add(1)
 }
 
 for i := 0; i < 100; i++ {
 go wg.Done()
 }
 fmt.Println("exit")
 wg.Wait()
}
 
func add(wg sync.WaitGroup) {
 wg.Add(1)
}
 
 
func done(wg sync.WaitGroup) {
 wg.Done()
}

这个场景要解决的问题是:上一轮定时任务调用的函数没有执行完,就不执行,否则再次执行,而 sync.waitGroup 方式只解决了不重复执行,但是无法“丢弃”这次调用,而是放到队列等后面执行,这样也许会累积很多队列,这不是期望的。

因此,解决办法就是,在函数开始执行的时候,在 Redis 设置一个值表示未完成,执行结束的地方更新这个值为已完成,在每次执行最前面判断这个值的状态,如果是未完成,就直接返回 false.

大概流程:

// 执行具体游戏房间的npc刷新
func doNpcRefresh(roomid int) bool {
	status := getRefreshStatus(roomid)
	if status == "0" {
		fmt.Printf("房间%d刷新未完成,不进行新一轮刷新\n", roomid)
		return false
	}
	start := time.Now()
	fmt.Println("====================检测NPC刷新====================")
	setRefreshStart(roomid)
 //此处省略800子
	setRefreshDone(roomid)
	return true
}

如此一来,就解决了问题。

注意:如果进程被意外 kill 掉,会导致 Redis 中这个值的状态永远都是未完成,那么重启服务后也就无法重新调用同一个函数了。这是个需要解决的问题。不过本场景暂时不需要考虑这种情况。


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
5019 次点击
9 回复 | 直到 2020年10月16日 16:52:32
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏