[英]How to run sequential Tasks in an ExecutorService
我看到了實現這一目標的三種主要方法。
這有點像你正在做的事情。 為每個玩家創建一個線程,將工作單元分派給它; 這本質上是連續的。
它可能無法很好地擴展到數百/數千個玩家(數百個活動線程通常不會嚇到現代硬件 - 盡管它可能不是很有效)。
但是代碼的可讀性和簡潔性可能是其他解決方案無法比擬的。
如果每個玩家一個線程是不可能的,那么我們將不得不共享線程,一個線程將處理多個玩家。
關鍵是讓給定的線程處理給定玩家的每個任務,從而實現串行執行。
我想到了三種構建它的方法......
如果你的球員有一些東西可以分組(例如一個團隊,甚至只是一個創建日期)......然后按組重新分組你的球員,並實施“每組線程”模式。
唯一的關鍵問題是擁有大致相同大小的組,以便平均分擔負載。
幾乎在每個解決方案中都會遇到的另一個問題是關閉組的線程(您怎么知道您想要處理的所有內容何時完成?)。
這就是“自己動手”。 它的要點是
fixedThreadPool
,比如說有 4 個線程。BlockingQueue
來保存每個工作單元PlayerWorker
實例並將它們發送到線程池執行,上面的每個BlockingQueue
。 這些工作者的實現是從隊列之一中提取數據並執行它。Math.abs(id % 4)
th 隊列PlayerWorker
和線程池這是很多工作,所以......
有些人已經為你做了。 演員模式非常適合這個問題。 您可能應該查看 Akka 和所謂的ConsistentHashingRoutingLogic
,它幾乎是一對一的映射,至少在概念上是我剛剛描述的。
如果我們退后一點,我們實際上並不關心線程。 我們關心串行執行。
因此,我們只需要一種在其他工作完成后執行某些工作的方法。 應該只是回電!
我們有CompletableFuture
(更不用說框架)。
那么為什么不為每個玩家創建一個CompletableFuture
,並且每次要為該玩家完成一個新的工作單元時,請使用CompletableFuture.thenApply
或thenApplyAsync
。
通過將執行分派到適當大小的執行池,並讓框架完成工作,任務將一個接一個地串行執行。
您可以為每個玩家創建一個singleEventExecutorService
。
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());
}
}
盡管對於 600 名玩家來說,這可能比單線程執行器表現得更糟。 但是,您可以通過某種方式對玩家進行分組,以便合理數量的玩家共享一個執行者。
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());
}
}
如果玩家在運行時動態變化,這可能會成為一個問題,因為這樣你最終可能會用一個線程處理很多玩家,而另一個組隨着時間的推移變得空了。
這真的取決於你的實際情況。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.