0
\$\begingroup\$

I am recently working on a server for a game (1 vs 1 with observers) that shall support parallel games and I wonder whether it is more efficient to

  1. create 1 extra thread per game/lobby or to
  2. let one Thread handle all the Input (the tcp-output will be a separate thread anyway)

The recent structure in brief (supporting only one game), the server receives and queues up all input, the logic-thread takes the queue's head and handles it, all output is queued up and handled by another thread. At this time we already got 3 threads running (one is the server itself). Threads are handled by ExecutorService. I wonder if it makes sense to fork in the logic-thread when I assume that the machine the game will run on later might have 2 cpu cores and be 10 years old in average.

Also, I am not sure - if I use one thread per lobby, how to determine how many games can run parallel and how many players/observers can reasonably attend one gamelobby at once.

What bothers me is that even if I test the limits on my machines that doesn't mean that it'll work elsewhere.

So, let's talk numbers.

Say I want to run 2, 20 or 100 games parallel without any observers, would you recommend option 1 or option 2?

Now we add observers, and now we add observers can also chat, what architecture would now be more reasonable and what do you think are reasonable limits then regarding the amount of parallel gamelobbies/running games and observers?

Additional question: When I have the class of one thread hold a queue and the other one takes from it, will this slow down the thread of which' class a queue's element was taken, or is that irrelevant, and if so, due to what?

\$\endgroup\$
0
\$\begingroup\$

I am not sure - if I use one thread per lobby, how to determine how many games can run parallel and how many players/observers can reasonably attend one gamelobby at once.

You can't be sure without testing it. Depending on how much your gameserver actually does, a thread might be idle most of the time or it might constantly do heavy number crunching. There is no rule of thumb here. Every game is different.

If you want to test it without managing hundreds of human testers, write a headless bot client which is able to connect to your server, enter a game and simulate human input. It doesn't need to play the game well, it just needs to generate a realistic server load. Run a couple instances of them to stress-test your server.

However, if you want to minimize CPU load, then you should generally not use more threads than you have CPU cores. The reason is that switching a CPU core from one thread to another is a surprisingly heavy operation. So you want to avoid thread context switches if possible. Thankfully, Java already has a built-in solution for this: The ThreadPoolExecutor executor service. What this actually does is enque your Runnables on multiple threads so the CPU does not need to switch context (This is also known as the "Fibers" pattern).

Now do you put your separate games into individual Runnables or do you have one Runnable which handles them all in a loop?

Considering that game lobbies likely do not share much write-acccess to data, they are a perfect candidate for a unit of parallelization. But if you assume that your game will run on a server with just two cores, it might make sense to dedicate one thread to running the game(s) logic and another thread to handle network IO. In that case you might want to opt for one thred which updates all active games in sequential order.

Now we add observers, and now we add observers can also chat, what architecture would now be more reasonable

Architecture-wise, observers should generally be implemented as another kind of player, just with different functionality.

Is the chat supposed to be global or bound to each game? If it is game-internal, it should be yet another part of the game update method. If you want a global chat, then I would recommend to have a separate chat-thread to handle global chat, because as mentioned before you always want to minimize data exchange between threads.

\$\endgroup\$
  • \$\begingroup\$ The chat is bound to each game. thanks so far. \$\endgroup\$ – Melissa Loos Apr 11 at 16:28
  • \$\begingroup\$ Does this mean that when I use the jvm-executor-service, I can implement like a hundred threads in parallel without causing heavy cpu load? What I mean is, I thought of writing a GameClass that organizes itself by running through a loop. When it comes to understand and editing the code this seems to be a lot more of a no-brainer than a single-game-logic where I as the developer have to keep track of the context and perform the context switches myself. That's why I wonder if a structure like that may still perform well. Regarding the thread activity, i guess they'd be idle most of the time. \$\endgroup\$ – Melissa Loos Apr 11 at 16:36
  • \$\begingroup\$ @MelissaLoos ExecutorService is an interface, not a class. But among the classes which implement that interface are some which implement something like that. For example, when you create a ThreadPoolExecutor with 4 threads and submit 100 Runnables to it, it will start 4 threads and each thread will process runnables in sequence. This is of course going to cause heavy CPU load - maxing out CPU load is the point of using parallelization. \$\endgroup\$ – Philipp Apr 11 at 16:46
  • \$\begingroup\$ thanks. that made things clearer. \$\endgroup\$ – Melissa Loos Apr 11 at 19:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.