Each ‘Room’ class instance needs to call the method ‘ProcessRoom’. I am currently overthinking something and would like another persons opinion.
One of the constant things here is ProcessRoom gets called, either way this method will always get called on all instances of the Room class, and it has to be ran every 500 milliseconds.
The thing I am having a dilemma about is if I should give each room class their own instance of System.Threading.Timer
and run it every 500 milliseconds.
My other options is I have the RoomManager class (the class that holds all the Room instances in a dictionary) have another instance of System.Threading.Timer
run every 500 milliseconds and do a foreach on all the rooms in a dictionary?
So I guess my questions are, would it be more benificial to have a foreach just for the performance side of things, or is there some sort of performance gain in giving each room its own thread? I plan to have around 20 – 200 rooms open at a time, so that’s up to 200 threads every 500ms.
I’m not good with multithreading and timers, so if theres something better I can use other than a timer in either circumstances, can someone shine some light?
public void ProcessRoom() { if (mDisposed) return; try { if (GetRoomUserManager().GetRoomUsers().Count == 0) IdleTime++; else if (IdleTime > 0) IdleTime = 0; if (RoomData.HasActivePromotion && RoomData.Promotion.HasExpired) { RoomData.EndPromotion(); } if (IdleTime >= 60 && !RoomData.HasActivePromotion) { Server.GetGame().GetRoomManager().UnloadRoom(this); return; } try { GetRoomItemHandler().OnCycle(); } catch (Exception e) { ExceptionLogger.LogException(e); } try { GetRoomUserManager().OnCycle(); } catch (Exception e) { ExceptionLogger.LogException(e); } try { GetRoomUserManager().SerializeStatusUpdates(); } catch (Exception e) { ExceptionLogger.LogException(e); } try { _gameItemHandler?.OnCycle(); } catch (Exception e) { ExceptionLogger.LogException(e); } try { GetWired().OnCycle(); } catch (Exception e) { ExceptionLogger.LogException(e); } } catch (Exception e) { ExceptionLogger.LogException(e); OnRoomCrash(e); } }
The Manager way, I just create a System.Threading.Timer and call the OnTimer every 500ms.
public void OnTimer() { try { foreach (Room Room in _rooms.Values.ToList()) { if (Room.isCrashed) continue; if (!Room.IsProcessing) { Room.ProcessRoom(); } else { Room.IsLagging++; if (Room.IsLagging >= 30) { Room.isCrashed = true; UnloadRoom(Room); } } } } catch (Exception e) { ExceptionLogger.LogException(e); } }
Or I give each room class a System.Threading.Timer, inside a class called ‘RoomWorker’ which every ‘Room’ instance will have one.
public class RoomWorker { private readonly Room _roomInstance; private readonly Timer _timer; private const int TimeIntervalInMilliseconds = 500; private bool _timerRunning; private int _lagCount; public RoomWorker(Room room) { _roomInstance = room; _timer = new Timer(Callback, null, TimeIntervalInMilliseconds, Timeout.Infinite); } private void Callback(Object state) { var watch = Stopwatch.StartNew(); try { if (_roomInstance.isCrashed) { return; } if (_timerRunning) { _lagCount++; if (_lagCount >= 30) { _roomInstance.isCrashed = true; Server.GetGame().GetRoomManager().UnloadRoom(_roomInstance); } return; } _lagCount = 0; _roomInstance.ProcessRoom(); _timerRunning = true; } catch { // ignored } finally { _timerRunning = false; _timer.Change(Math.Max(0, TimeIntervalInMilliseconds - watch.ElapsedMilliseconds), Timeout.Infinite); } } }