我有一個非常簡單直接的服務器(使用kryonet)。客戶只存儲汽車的當前狀態(x,y,角度等),併發送加速和轉彎請求。如何在不使用阻塞隊列的情況下將消息傳遞給另一個線程?
服務器正在接收請求並將它們添加到物理線程消耗並讀取和更新的ArrayBlockingQueue。
添加其他玩家時,遊戲速度減慢將近一倍。我已經排除了很多事情(我有所有的更新和封裝發送在60Hz扼殺)。
我懷疑使用阻塞隊列阻塞太多,導致放緩。
如何將客戶端請求發送到物理線程而不會阻塞問題?
我有一個非常簡單直接的服務器(使用kryonet)。客戶只存儲汽車的當前狀態(x,y,角度等),併發送加速和轉彎請求。如何在不使用阻塞隊列的情況下將消息傳遞給另一個線程?
服務器正在接收請求並將它們添加到物理線程消耗並讀取和更新的ArrayBlockingQueue。
添加其他玩家時,遊戲速度減慢將近一倍。我已經排除了很多事情(我有所有的更新和封裝發送在60Hz扼殺)。
我懷疑使用阻塞隊列阻塞太多,導致放緩。
如何將客戶端請求發送到物理線程而不會阻塞問題?
我發現了這個錯誤。我需要以一種不同的方式來扼制物理模擬(不是用world.step()函數,而是限制被調用的頻率)。這是這樣的。
while(true)
{
delta = System.nanoTime() - timer;
if(delta >= 16666666) // 60 Hz
{
world.step(1.0f, 6, 2);
processAndUpdateYourData();
timer = System.nanoTime();
}
}
然後,我需要調整所有的物理數字,讓他們感覺自然與這種配置。
你的問題預設了一個實現 - 你最好問「爲什麼我的代碼太慢?」。
阻塞隊列是實現生產者/消費者模式的最有效方式。
我會添加更多的消費者線程 - 嘗試添加儘可能多的消費者線程,因爲有處理器核心 - 即Runtime.getRuntime().availableProcessors()
。
由於客戶端數據包的接收者是由kryonet庫實現的,因此我無法向服務器端添加更多線程。物理線程需要是1線程來模擬世界。 –
您可以使用干擾器(環形緩衝區),一個用於實現隊列的無鎖機制。請參閱:
使用環形緩衝區(破壞者的心臟)可以消除併發鎖定帶來的極少量時間,但我無法想象時間會以每秒60個消息的速度減慢50%。 –
+1爲酷紙。 :) –
確保您所創建的隊列可滿足所有的客戶足夠的位置。如果因爲客戶端太多而使隊列變滿,則嘗試插入命令時會阻塞隊列。如果這不是問題,這意味着你的物理(消費者)線程沒有跟上請求,你需要確保它獲得更多的處理時間。
我可以看到隊列是否太滿。它會拋出一個異常並導致客戶端崩潰(當前)。而且這一刻不會發生。 –
我懷疑使用阻塞隊列阻塞太多,導致減速。
你懷疑是錯的。下面的測試程序,通過推動的ArrayBlockingQueue百萬整數:
public class ArrayBlockingQueuePerfTest {
int maxi = 1000000;
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(1000,
true);
Thread sender = new Thread("sender") {
public void run() {
try {
for (int i = 0; i < maxi; i++) {
queue.offer(i, 1, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
};
};
Thread receiver = new Thread("receiver") {
public void run() {
try {
int count = 0;
long sum = 0;
while (count < maxi) {
sum += queue.poll(1, TimeUnit.SECONDS);
count++;
}
System.out.println("done");
System.out.println("expected sum: " + ((long) maxi) * (maxi - 1)/2);
System.out.println("actual sum: " + sum);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
};
};
public ArrayBlockingQueuePerfTest() {
sender.start();
receiver.start();
}
public static void main(String[] args) {
new ArrayBlockingQueuePerfTest();
}
}
在我的筆記本電腦,它終止在幾秒鐘。因此,無論性能瓶頸在哪裏,都不是ArrayBlockingQueue,它可以處理比您需要的數據量高出至少3個數量級的吞吐量。換句話說,即使你找到了一個根本不需要執行時間的線程通信方法,那隻會使你的程序加速至多0.1%。
家庭作業,這和所有其他性能問題:解決在現有代碼的任何性能問題時,第一步是措施代碼的哪些部分是緩慢的,因爲通常情況下,它是不是其中一個希望。探查器極大地簡化了這項任務。
我已經通過JVM分析器分析了代碼,我有大日誌,他們目前沒有向我展示任何東西。當添加第二名球員時,沒有差別,沒有秒殺。我現在懷疑問題不在於服務器,而在於客戶端。但非常感謝您的回覆。 –
讓我直截了當地說:你希望每秒通過一個阻塞隊列傳遞60條消息,並認爲它是瓶頸? – meriton
我不明白你的問題,我很新的阻止名單,所以請不要這樣做。 –
如果隊列沒有填充,那麼你沒有阻塞。你的CPU運行在100%嗎?當你添加一個玩家時,你有多少玩家? –