I was going to paste a lot of my game loop code here, but asterite (and 99% of devs) prefer REDUCED code. So I hope I reduced it enough.
TICKRATE = 1/25
class Client
property user_id = 0
def initialize(@user_id)
start_looping_fiber
end
def start_looping_fiber
delay(1) {
pp "I am called once per second! #{user_id} I AM INSIDE A DELAY FIBER!!"
spawn start_looping_fiber # WE ARE OFF TO THE RACESSSS
}
end
# Called every second
def update_second(delta)
pp "I am called once per second! #{user_id}"
end
end
class Server
property players = Hash(Int32, Client).new
def initialize
players[1] = Client.new(1)
players[2] = Client.new(2)
game_loop
end
# PRETEND THIS HAS A PROPER DELTA FOR BREVITY SAKE
def game_loop
second_counter = 0
loop do
second_counter += TICKRATE
if second_counter > 1
players.each do |player_id, player_obj|
player_obj.update_second(TICKRATE)
if player_id == 1
players.delete player_id
player_obj.start_looping_fiber.cancel
pp "#{player_id} has been deleted"
end
end
second_counter = 0
end
sleep TICKRATE
end
end
end
Server.new
What’s the performance difference between start_looping_fiber, compared to just calling update_second based on a counter?
If there is a performance difference or not, which way is more proper? Example, what if you have 1000 players. delay would create 1000 fibers per second, instead of just using .each, and calling the update_second method.
I’ve noticed if I call player_obj.start_looping_fiber.cancel, the fiber still runs. Is that intended?
Depends on how your game scales per player. I’d imagine a Crystal app could run okay on 1000 fibers, but if there are multiple fibers per player, you may start noticing issues at scale.
Fibers are cheap, but they’re not free. They add CPU time for the scheduler to manage them and if you’re spinning them up and letting them die often, they’ll have to be GCed as well, so it’s entirely possible that update_second will be more performant.
To be real, though, you should probably use whichever one makes you happier to work with. Just make sure you make affordances for eliminating the extra fibers if you need to in order to gain some performance, assuming you choose that route.
Thanks. I like the update_second way. I’ll probably stick to that. I just recently find out about delay from a SO post by @jhass, and figured I’d see if I could/should incorporate it into my game logic
I don’t know about 1000 players because I can’t set ulimit to a high enough value in WSL, but I can confirm that 500 with multiple fibers per player (doing stuff) works without lag even without --release in a fairly involved server.