I’m looking to improve the performance, quality and effiency of the following code. I have a server I use for my game that manages all the players connected plus a few other things, which have Manager classes for each category.
Some of these manager classes have certain operations to complete, which I use a task for.
Instead of having a task for each manager class, I currently have a parent class called ‘game’ and run a task from that class only, then calling each method inside the manager classes for cycle on the same task I declared in the game class.
My reasoning for this question is I’m unsure if I should be using 1 task for the whole operation, or should I give the manager classes their own task. I’m looking for someone to explain the ups and downs for doing this and which one I should opt for.
Is it a Task that I should even be using, I’ve heard that maybe a thread could also be used, but I just don’t have the advanced knowledge of the language to decide for myself.
I’m doing this as a personal project for a hobby, so I don’t know much about the language in terms of the advanced end of things. The methods shouldn’t take long and its usually checking basics things like movement requests, packets, and looping through dictionary’s and checking things.
One more thing that I was unsure of is some calls require different intervals which made me wonder is it a good idea blocking the Task until its needed, or is there some better way to do this? some only run every 30 seconds, some only run every 0.5 seconds, I’ve added stopwatch’s and if statements to block the methods if its not time for it to run, maybe this can also be avoided in changing the way it works for the better?
I’m just not sure if moving to multiple tasks is the right choice, on one hand you have the multiple intervals issue, but then the overhead of managing multiple tasks, but is that a bad thing?
Anyone who can give some insight please do, thank you.
So a quick summary of the question, should I be using a Task, Thread or Timer? and finally, should I be using 1 task across just the game class, or would giving the manager classes their own tasks be better or over kill?
public class Game() { public Game() { _gameCycle = new Task(GameCycle); _gameCycle.Start(); _cycleActive = true; } private void GameCycle() { while (_cycleActive) { _cycleEnded = false; PlayerManager.OnCycle(); RoomManager.OnCycle(); _cycleEnded = true; Thread.Sleep(25); } } public void StopGameLoop() { _cycleActive = false; while (!_cycleEnded) { Thread.Sleep(25); } } } public class PlayerManager { private readonly Queue timedOutConnections; private readonly Stopwatch clientPingStopwatch; private readonly HashSet<Player> _players; public PlayerManager() { clientPingStopwatch = new Stopwatch(); clientPingStopwatch.Start(); _players = new HashSet<Player>(); } public void OnCycle() { CheckTimeouts(); CheckConnections(); } private void CheckTimeouts() { lock (timedOutConnections.SyncRoot) { if (timedOutConnections.Count <= 0) return; lock (timedOutConnections.SyncRoot) { while (timedOutConnections.Count > 0) { Player player = null; if (timedOutConnections.Count > 0) player = (Player)timedOutConnections.Dequeue(); if (player != null) player.Dispose(); } } } } private void CheckConnections() { if (clientPingStopwatch.ElapsedMilliseconds >= 30000) { clientPingStopwatch.Restart(); List<Player> ToPing = new List<Player>(); lock (SyncRoot) { foreach (Player player in _players.ToList()) { if (player.PingCount < 6) { player.PingCount++; ToPing.Add(player); } else { lock (timedOutConnections.SyncRoot) { timedOutConnections.Enqueue(player); } } } } foreach (Player player in ToPing.ToList()) { try { player.SendPacket(new PongComposer()); } catch { lock (timedOutConnections.SyncRoot) { timedOutConnections.Enqueue(player); } } } } } } public class RoomManager { private DateTime _lastExecution; private readonly ConcurrentDictionary<int, Room> _rooms; public RoomManager() { _rooms = new ConcurrentDictionary<int, Room>(); } public void OnCycle() { CheckRooms(); } public void CheckRooms() { TimeSpan sinceLastTime = DateTime.Now - _lastExecution; if (sinceLastTime.TotalMilliseconds >= 500) { _lastExecution = DateTime.Now; foreach (Room room in _rooms.Values.ToList()) { if (room.isCrashed) continue; if (room.ProcessTask == null || room.ProcessTask.IsCompleted) { room.ProcessTask = new Task(room.ProcessRoom); room.ProcessTask.Start(); room.IsLagging = 0; } else { room.IsLagging++; if (room.IsLagging >= 30) { room.isCrashed = true; UnloadRoom(room); } } } } } }