Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

目标和参考资料 #1

Open
guonaihong opened this issue May 28, 2020 · 9 comments
Open

目标和参考资料 #1

guonaihong opened this issue May 28, 2020 · 9 comments

Comments

@guonaihong
Copy link
Contributor

guonaihong commented May 28, 2020

目标

  • 用go使用5级时间轮实现定时器
  • 如有可能效率追求fast fast fast

参考资料

论文

http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf

参考项目

参考书本

  • 书名
    深入linux内核架构(Professional Linux Kernel Architecture)(第15章时间管理)
    tv1 0-255

  • 范围
    tv2 2的8次方-2的14次方-1
    tv3 2的14次方-2的20次方-1
    tv4 2的20次方-2的26次方-1
    tv5 2的26次方-2的32次方-1

  • 移动
    第一组的内容在最多256个时间周期之后就会耗尽,必须将后续各组的定时器依次前推,重新补足第一组。在第一组的索引位置恢复到初始位置0之后,会将第二组中一个数组项的所有定时器补充到第一组。这种做做法,解释了为什么各组选择了不同的时间间隔。因为第一组的各数组项可能有256个不同的到期时间,而第二组中一个数组项的数据就足以填充整个第一组的整个数组。该道理同样适用于后续各组。第三组的一个数组项的数据同样足以填充整修第二个组,第四组的一个数组项也足以填充整修第三组,而第五组的一个数组项也足以填充整个第四组。

后续各组的数组位置并非随机选择的,其中的索引项仍然发挥了作用。但索引项的值不再是每个时钟周期加1,而是第256的i-1次方

  • cascade函数用于从指定组取得定时器补充到前一组
@guonaihong guonaihong changed the title 目标 目标和参考资料 Jun 8, 2020
@kingname
Copy link

感谢。、

@guonaihong
Copy link
Contributor Author

@kingname 😊

@zhendliu
Copy link

zhendliu commented Jul 14, 2020

我的使用场景是这样,面对很多网络连接,先声明一个NewTimer ,然后用一个协程去Run,而后每一个连接打开的时候,使用TM.ScheduleFunc() 对每个连接进行不同时间的心跳,测试的时候是每个连接到来,每5秒下发一次心跳,一个连接没问题,超过一个连接,其他的连接发送了几次心跳后会莫名停止,就是TM.ScheduleFunc中执行的函数不执行了,众多连接只有一个连接能发送心跳,其他的都不能,请赐教,是不是我用的方式不对。

@guonaihong
Copy link
Contributor Author

@jungeshidai go.mod是v0.0.4吧?可否发下调用代码,我测试下。

@zhendliu
Copy link

zhendliu commented Jul 14, 2020

@jungeshidai go.mod是v0.0.4吧?可否发下调用代码,我测试下。我使用的版本是1.14 ,随便写了个测试代码。调试工具是(以太网调试助手SocketTool_NoAD),很多连接时,每个连接大约都能跑1分钟所有,过了一分钟,只剩下一个连接能发送心跳了。

package main

import (
	"encoding/hex"

	"flag"
	"fmt"
	"github.com/antlabs/timer"
	"net/http"
	_ "net/http/pprof"

	"log"
	"time"

	"github.com/panjf2000/gnet"
)





var (
	SetBytes, _ = hex.DecodeString("01030000001445C5")
	TM          = timer.NewTimer()
)

type iotServer struct {
	*gnet.EventServer
}

func (es *iotServer) OnInitComplete(srv gnet.Server) (action gnet.Action) {
	log.Printf("Iot server is listening on %s (multi-cores: %t, loops: %d)\n", srv.Addr.String(), srv.Multicore, srv.NumEventLoop)
	go ProfStart()
	//启动时间轮
	go TimeStart()
	return
}

/*
 消息处理函数
*/
func (es *iotServer) React(data []byte, c gnet.Conn) (out []byte, action gnet.Action) {
	return
}

/*
	连接打开时
*/
func (es *iotServer) OnOpened(c gnet.Conn) (out []byte, action gnet.Action) {
	TM.ScheduleFunc(5*time.Second, func() {
		fmt.Printf("开始下发指令:[%s]\n", c.RemoteAddr())
		if c == nil {
			return
		}
		err := c.AsyncWrite(SetBytes)
		fmt.Printf("时间[%s]:[%s]:下发指令:%x\n", time.Now().Format("2006-01-02 15:04:05"), c.RemoteAddr(), SetBytes)
		if err != nil {
			c.Close()
		}
	})

	return
}
/*
	连接退出时
*/
func (es *iotServer) OnClosed(c gnet.Conn, err error) (action gnet.Action) {
	return
}
/*
	程序性能监控模块启动
*/
func ProfStart() {
	http.ListenAndServe("0.0.0.0:6060", nil)
}
/*
	时间轮模块启动
*/
func TimeStart() {
	TM.Run()
}

func main() {
	var port int
	var multicore bool

	flag.IntVar(&port, "port", 501, "--port 9000")
	flag.BoolVar(&multicore, "multicore", true, "--multicore true")
	flag.Parse()
	iot := new(iotServer)
	log.Fatal(gnet.Serve(iot, fmt.Sprintf("tcp://:%d", port), gnet.WithMulticore(multicore)))

}

@guonaihong
Copy link
Contributor Author

ok,我看下

@guonaihong
Copy link
Contributor Author

@jungeshidai 下载v0.0.5版本看下呢,刚刚处理了下周期性定时器边界问题。

@zhendliu
Copy link

@guonaihong 目前测试看,问题已经修复,之前的0.4版本我已经再测试环境测试了性能问题,长期运行CPU占用0.7左右的。马上发布0.5的版本到测试服务器上测试,有问题再向您反馈,感谢。

@guonaihong
Copy link
Contributor Author

@jungeshidai ok,客气了。
对于上面的代码有个建议,在tcp连接关闭时,可以把这个tcp绑定的time wheel node也关闭。ScheduleFunc会返回time wheel节点对象,调用Stop()就是关闭。

提问题可以建新的issue。一个问题一个issue,这样以后也可以帮助到别人检索问题和帮助。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants