删除goroutineid及相关逻辑

修改世界运行逻辑循环从使用睡眠改为使用Ticker(睡眠会有因go调度产生的额外几毫秒时间问题)
This commit is contained in:
walker 2023-09-20 15:30:51 +08:00
parent c3b9d965c6
commit cbb36d8c08
5 changed files with 86 additions and 70 deletions

View File

@ -47,34 +47,22 @@ func processAllEvents(w World) {
// 订阅该类型的事件 // 订阅该类型的事件
func (me *EventType[T]) Subscribe(wd World, subscriber Subscriber[T]) { func (me *EventType[T]) Subscribe(wd World, subscriber Subscriber[T]) {
if wd.GoroutineId() == currentGoId() { wd.(*world).chanManageEvent <- func() {
me.subscribe(wd, subscriber) me.subscribe(wd, subscriber)
} else {
wd.(*world).chanManageEvent <- func() {
me.subscribe(wd, subscriber)
}
} }
} }
// 取消订阅该类型的事件 // 取消订阅该类型的事件
func (me *EventType[T]) Unsubscribe(wd World, subscriber Subscriber[T]) { func (me *EventType[T]) Unsubscribe(wd World, subscriber Subscriber[T]) {
if wd.GoroutineId() == currentGoId() { wd.(*world).chanManageEvent <- func() {
me.unsubscribe(wd, subscriber) me.unsubscribe(wd, subscriber)
} else {
wd.(*world).chanManageEvent <- func() {
me.unsubscribe(wd, subscriber)
}
} }
} }
// 发布该类型的事件 // 发布该类型的事件
func (me *EventType[T]) Publish(wd World, event *T) { func (me *EventType[T]) Publish(wd World, event *T) {
if wd.GoroutineId() == currentGoId() { wd.(*world).chanManageEvent <- func() {
me.publish(wd, event) me.publish(wd, event)
} else {
wd.(*world).chanManageEvent <- func() {
me.publish(wd, event)
}
} }
} }

View File

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"runtime"
"time" "time"
"joylink.club/ecs" "joylink.club/ecs"
@ -14,36 +15,57 @@ type FireSwitchDcEvent struct {
var fireSwitchDcEventType = ecs.NewEventType[FireSwitchDcEvent]() var fireSwitchDcEventType = ecs.NewEventType[FireSwitchDcEvent]()
type SwitchSystem struct { type SwitchSystem struct {
count int
} }
func (me *SwitchSystem) WhenFireSwitchDcEvent(w ecs.World, event FireSwitchDcEvent) { func (me *SwitchSystem) WhenFireSwitchDcEvent(w ecs.World, event FireSwitchDcEvent) {
fmt.Println("====>>>world-", w.GoroutineId(), " SwitchSystem 处理事件 ", event) fmt.Println("====>>>world-", w.Id(), " SwitchSystem 处理事件 ", event)
} }
func (me *SwitchSystem) Update(w ecs.World) { func (me *SwitchSystem) Update(w ecs.World) {
fmt.Println("====>>>world-", w.GoroutineId(), " SwitchSystem update ") me.count += 1
fmt.Println("time: ", time.Now().Format(time.StampMilli), "====>>>world-", w.Id(), " SwitchSystem update , count: ", me.count)
} }
var switchSystem = &SwitchSystem{} // var switchSystem = &SwitchSystem{}
func NewSwitchSystem() *SwitchSystem {
return &SwitchSystem{
0,
}
}
var ( var (
wd1 = ecs.NewWorld(1000) wd1 = ecs.NewWorld(1)
wd2 = ecs.NewWorld(1000) wd2 = ecs.NewWorld(20)
) )
// //////////////////////////////////////// // ////////////////////////////////////////
func main() { func main() {
go world1() // go world1()
go world2() // go world2()
time.Sleep(4 * time.Second) // time.Sleep(4 * time.Second)
fireSwitchDcEventType.Publish(wd1, &FireSwitchDcEvent{Dc: true}) // fireSwitchDcEventType.Publish(wd1, &FireSwitchDcEvent{Dc: true})
fireSwitchDcEventType.Publish(wd2, &FireSwitchDcEvent{Dc: false}) // fireSwitchDcEventType.Publish(wd2, &FireSwitchDcEvent{Dc: false})
time.Sleep(30 * time.Second)
fmt.Println("当前运行系统为:", runtime.GOOS)
wd1.AddSystem(NewSwitchSystem())
wd1.StartUp()
//
wd2.AddSystem(NewSwitchSystem())
wd2.StartUp()
fmt.Println("开始", time.Now())
time.Sleep(5 * time.Second)
fmt.Println("结束", time.Now())
} }
func world1() { func world1() {
world := wd1 world := wd1
world.StartUp() world.StartUp()
// //
switchSystem := NewSwitchSystem()
world.AddSystem(switchSystem) world.AddSystem(switchSystem)
// //
fireSwitchDcEventType.Subscribe(world, switchSystem.WhenFireSwitchDcEvent) fireSwitchDcEventType.Subscribe(world, switchSystem.WhenFireSwitchDcEvent)
@ -58,6 +80,7 @@ func world2() {
world := wd2 world := wd2
world.StartUp() world.StartUp()
// //
switchSystem := NewSwitchSystem()
world.AddSystem(switchSystem) world.AddSystem(switchSystem)
fireSwitchDcEventType.Subscribe(world, switchSystem.WhenFireSwitchDcEvent) fireSwitchDcEventType.Subscribe(world, switchSystem.WhenFireSwitchDcEvent)
// //

5
go.mod
View File

@ -2,4 +2,7 @@ module joylink.club/ecs
go 1.20 go 1.20
require github.com/yohamta/donburi v1.3.8 require (
github.com/yohamta/donburi v1.3.8
golang.org/x/time v0.3.0
)

2
go.sum
View File

@ -3,4 +3,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/yohamta/donburi v1.3.8 h1:ca4NuhzJ8Jeb6GAEf6ecksa+l8JWaAnr0WLqG20TimU= github.com/yohamta/donburi v1.3.8 h1:ca4NuhzJ8Jeb6GAEf6ecksa+l8JWaAnr0WLqG20TimU=
github.com/yohamta/donburi v1.3.8/go.mod h1:5QkyraUjkzbMVTD2b8jaPFy1Uwjm/zdFN1c1lZGaezg= github.com/yohamta/donburi v1.3.8/go.mod h1:5QkyraUjkzbMVTD2b8jaPFy1Uwjm/zdFN1c1lZGaezg=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

View File

@ -1,11 +1,8 @@
package ecs package ecs
import ( import (
"bytes"
"fmt" "fmt"
"log" "log"
"runtime"
"strconv"
"time" "time"
"github.com/yohamta/donburi" "github.com/yohamta/donburi"
@ -47,18 +44,19 @@ type World interface {
SetSpeed(speed float64) error SetSpeed(speed float64) error
AddSystem(sys ...ISystem) AddSystem(sys ...ISystem)
Close() Close()
// 世界时间间隔
Tick() int Tick() int
Running() bool Running() bool
GoroutineId() uint64
} }
type world struct { type world struct {
gId uint64 world donburi.World
world donburi.World systems []ISystem
systems []ISystem state WorldState
state WorldState tick int
tick int lastTick time.Time
speed float64 ticker *time.Ticker
speed float64
quit chan struct{} quit chan struct{}
chanManageEvent chan ManageEventFunc chanManageEvent chan ManageEventFunc
@ -69,20 +67,21 @@ func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
return &ComponentType[T]{ct} return &ComponentType[T]{ct}
} }
// 初始化一个新World
// tick 单位为ms且必须大于0
func NewWorld(tick int) World { func NewWorld(tick int) World {
return &world{ return &world{
world: donburi.NewWorld(), world: donburi.NewWorld(),
systems: make([]ISystem, 0), systems: make([]ISystem, 0),
state: Init, state: Init,
tick: tick, tick: tick,
lastTick: time.Now(),
ticker: time.NewTicker(time.Duration(tick) * time.Millisecond),
speed: 1, speed: 1,
quit: make(chan struct{}), quit: make(chan struct{}),
chanManageEvent: make(chan ManageEventFunc, 1024), chanManageEvent: make(chan ManageEventFunc, 1024),
} }
} }
func (w *world) GoroutineId() uint64 {
return w.gId
}
func (w *world) Running() bool { func (w *world) Running() bool {
return w.state == Running return w.state == Running
} }
@ -158,9 +157,20 @@ func (w *world) SetSpeed(speed float64) error {
return fmt.Errorf("速度必须在[%f, %d]之间", SpeedMin, SpeedMax) return fmt.Errorf("速度必须在[%f, %d]之间", SpeedMin, SpeedMax)
} }
w.speed = speed w.speed = speed
fmt.Println("更新速度实际tick=", w.ActualTick())
w.ticker.Reset(time.Duration(w.ActualTick()) * time.Millisecond)
return nil return nil
} }
// 世界实际运行频率
func (w *world) ActualTick() int64 {
tick := int64(float64(w.tick) / (w.speed))
if tick <= 0 {
return 1
}
return tick
}
// 启动世界,世界逻辑开始执行且世界为运行状态 // 启动世界,世界逻辑开始执行且世界为运行状态
func (w *world) StartUp() { func (w *world) StartUp() {
if w.state == Init { // 避免重复运行 if w.state == Init { // 避免重复运行
@ -196,30 +206,42 @@ func (w *world) processManageEventFuncs() {
} }
func (w *world) run() { func (w *world) run() {
w.gId = currentGoId()
for { for {
select { select {
case <-w.quit: // 退出信号 case <-w.quit: // 退出信号
// 仿真退出,更新状态
log.Println("仿真退出,id:", w.world.Id()) log.Println("仿真退出,id:", w.world.Id())
w.state = Closed w.state = Closed
default: default:
} }
if w.state == Error { if w.state == Error {
log.Println("世界错误,关闭世界,id:", w.world.Id()) // 世界错误,关闭世界
return return
} }
if w.state == Closed { if w.state == Closed {
log.Println("世界正常关闭,id:", w.world.Id()) // 世界正常关闭
return return
} }
<-w.ticker.C
if w.state == Pause { // 暂停不更新 if w.state == Pause { // 暂停不更新
log.Println("仿真暂停中,id:", w.world.Id()) // time.Sleep(1 * time.Millisecond)
sleep := int64(float64(w.tick) / (w.speed))
time.Sleep(time.Duration(sleep) * time.Millisecond)
continue continue
} }
start := time.Now() // dt := time.Since(w.lastTick).Milliseconds()
// fmt.Println("仿真更新,id:", info.id) // if dt >= w.ActualTick() {
// // fmt.Println("仿真更新,id:", info.id)
// w.lastTick = time.Now()
// for _, sys := range w.systems {
// sys.Update(w)
// }
// // 处理事件管理相关
// w.processManageEventFuncs()
// // 处理所有事件
// processAllEvents(w)
// }
// time.Sleep(15 * time.Millisecond)
for _, sys := range w.systems { for _, sys := range w.systems {
sys.Update(w) sys.Update(w)
} }
@ -227,27 +249,5 @@ func (w *world) run() {
w.processManageEventFuncs() w.processManageEventFuncs()
// 处理所有事件 // 处理所有事件
processAllEvents(w) processAllEvents(w)
// 执行逻辑花费时间单位ms
ot := time.Duration(time.Now().Nanosecond() - start.Nanosecond()).Milliseconds()
// 根据间隔和速度计算休眠时间
sleep := int64(float64(w.tick)/(w.speed)) - ot
if sleep > 0 {
time.Sleep(time.Duration(sleep) * time.Millisecond)
} else {
log.Println("仿真无休眠,id:", w.world.Id())
}
} }
} }
// 获取当前协程id
func currentGoId() (gid uint64) {
b := make([]byte, 16)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, err := strconv.ParseUint(string(b), 10, 64)
if err != nil {
panic(err)
}
return n
}