Saturday, February 18, 2017

java - Avoid threads/multithreading



So here is the thing: I have made a thread for each generator an outpost has. We have a total of 6 outposts , 5 generators each. 3 teams, engineers can only repair generators and prevent their overload. In order to make the whole generator logic I use threads. If the thread gets interrupted it means that the generator got prevented from being destroyed , if the thread is finished normally , the generator got destroyed and if the generator is destroyed an engineer can repair them. Is there any way of avoiding threads because in spite of high cpu usage there are also other thread issues.


The same thing happens with the shield regeneration of each player. I'll just post the code for this one:


public static void startRegenerate(final Player p){

if(already_regenerating_arraylist.contains(p.getId())){
return;
}


final int previous_shield_lvl = p.getShieldLevel();
final int previous_hp_lvl = (int) p.getHealth();

Thread reg = new Thread(){

@Override
public void run(){

already_regenerating_arraylist.add(p.getUniqueId());
try {

sleep(3000);
} catch (InterruptedException e1) {
}

for(;;){

if(p.getShieldLevel() >= 20){
p.setShieldLevel(20);
already_regenerating_arraylist.remove(p.getUniqueId());
break;

}

if(p.getHealth() < previous_hp_lvl || p.getShieldLevel() < previous_shield_lvl){
already_regenerating_arraylist.remove(p.getUniqueId());
break;
}

p.setFoodLevel(p.getFoodLevel() + 6);

try {

sleep(1000);
} catch (InterruptedException e) {
}
}

}

};

reg.start();

}

After having more than 50 players stuff stop working (lag , etc...)



Answer



Rule number one of multithreading: avoid it. You might think: "Well, there are things in my game which are supposed to happen simultaneously. Wouldn't it be much more intuitive when each thing happens in its own thread?" No, it's not. Using multithreading makes your program magnitudes more complex. You have no control over how much CPU time the operating system gives to each of your threads and when exactly it switches between them, so they will become out of sync unless you manually synchronize them by making them wait for each other to finish. This introduces very hard to reproduce bugs due to race conditions and deadlocks. Sure, there are language features like synchronized to avoid some of them, but these have pitfalls on their own and are easy to forget.


The only argument ever for using more than one thread is performance.


Use threading when you have some calculation which is so CPU-intense that you need more than one core. But in that case don't use more threads than the machine has (currently idle) CPU cores and make sure each thread is able to do a lot of work before being forced to yield or wait for another thread, or you will gain nothing except burdening the OS with additional thread context switches. That's likely what slows down your application.


Another reason to use threading is when you have any network, database or file IO and don't want your application to become unresponsive in the meantime. However, in that case most environments should provide an asynchronous API which does the dirty multithreading stuff for you. In Java, thats Non-blocking IO.


OK, so how else could you structure your application?


You could have a standard game loop.



while game is running
render a frame
check time elapsed since last gamestate update
update gamestate taking the elapsed time into account

give each object in your game an update() function and call that function of each object in a for-loop in your global update gamestate function.


There are two different approaches how to take the elapsed time into account. Either the delta-t model where you pass the difference between real-world time and processed time to the update-function and take it into account for all calculations, or the tick-model where you agree on the internal ticks-per-second rate with which your game logic works (usually 100), check how many ticks your simulation is behind real-time, and call the update-function that many times.


Which one is the better method depends on the game and your personal preference. I personally prefer the tick-method because it is a lot easier to write the update-functions when you don't have to take the delta-t factor into account for everything, but the delta-t method can sometimes (not always!) be a bit faster.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...