I would like to execute different tasks for each player in an event executor, but make sure that the tasks submitted for each player are in order. Here is a picture to hopefully explain in better.
Extra Information:
What I have tried:
Currently I am using Executors.newSingleThreadExecutor()
inside of each player object to mimic this functionality, but I don't think this will scale well with a lot of players. Hence why I am asking here to find a better method.
I see three main ways of achieving this.
This is a bit like what you are doing. Create a thread per player, dispatch work units to it; this is serial by nature.
It may not scale well to a few hundreds / thousands of players (a few hundred active threads usually do not scare mordern hardware - although it may not be really efficient).
But the readability and ligthness of the code will probably be unmatched by other solutions.
If a thread per player is not possible, then we will have to share threads, and a thread will deal with several players.
The key will be to have a given thread handle every task for a given player, so as to achieve serial execution.
Three ways of building this come to mind...
If your players have something to allow for grouping (eg a Team, or even just a creation date)... then regroup your players by group, and implement a "Thread per group" pattern.
The only key issue is to have groups of roughly the same size, so as to share the load evenly.
Another issue, that you will have in almost every solution, will be to shutdown the thread for the group (how do you know when everything you wanted to process is finished ?).
This is the "do it yourself way". The gist of it is
fixedThreadPool
, say with 4 threads.BlockingQueue
that will hold every work unitsPlayerWorker
instances and send them to the thread pool to being execution, one for each of the above BlockingQueue
. The implementation of these workers is to pull data from one of the queues and execute it.Math.abs(id % 4)
th queuePlayerWorker
and thread pool when everything is doneThis is a lot of work, so...
Some people have already done it for you. The actor pattern is a very good fit for this problem. You should probably check out Akka and what is called ConsistentHashingRoutingLogic
, which is a pretty much one to one mapping, conceptually at least, to what I just described.
If we step back a bit, we do not actually care about threads . We care about serial execution .
So we just need a way to perform some work after some other work is done. It should be just a call back !
And we have CompletableFuture
for that (not to mention frameworks).
So why not create one CompletableFuture
per player, and each time a new work unit is to be done for this player, use CompletableFuture.thenApply
or thenApplyAsync
.
By dispatching the executions to an appropriately sized execution pool, and letting the framework do the job, the tasks will be serially executed one after the other.
You can just create a singleEventExecutorService
for each player.
class PlayerEventHandler {
private Map<Player, ExecutorService> executors = new ConcurrentHashMap<>();
public void handleEvent(PlayerEvent e) {
ExecutorService executor = executors.computeIfAbsent(e.getPlayer(), Executors.newSingleThreadExecutor());
executor.submit(e.execute());
}
}
Although this would probably behave much worse for 600 players than a single thread executor. However, you can probably group the players in some way so that a reasonable amount of players share an executor.
class PlayerEventHandler {
private Map<PlayerGroup, ExecutorService> executors = new ConcurrentHashMap<>();
public void handleEvent(PlayerEvent e) {
PlayerGroup group = determineGroup(e.getPlayer());
ExecutorService executor = executors.computeIfAbsent(group, Executors.newSingleThreadExecutor());
executor.submit(e.execute());
}
}
This will probably become a problem if the players change dynamically during runtime, because then you can end up with a single thread handling a lot of players, while another group has become empty over time.
It really depends on your actual case.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.