我想設定一個服務器-多個客戶端系統。
情況
多個客戶端要與服務器啟動 TCP 套接字連接,服務器接受連接。(連接會保持很長時間)。我應該如何實作服務器套接字部分,以便它始終可以以最有效的方式立即接受新的客戶端連接(意思是,將負載分散到所有可用的內核上)。這些是我到目前為止找到的方法:具有未系結執行緒池的同步服務器套接字
對于每個客戶端連接,服務器使用未系結的執行緒池在新執行緒中創建一個新的服務器套接字。問題是當客戶端多的時候,執行緒太多,服務器處理不了(因為垃圾收集器?)具有固定執行緒池和 LinkedBlockingQueue 的同步服務器套接字
對于每個客戶端連接,服務器使用固定執行緒池在新執行緒中創建一個新的服務器套接字。當客戶端的數量多于固定執行緒池中的執行緒數時,客戶端必須等待執行緒再次可用。單執行緒上的異步服務器套接字
對于每個客戶端連接,服務器都會創建一個異步服務器套接字,因為這些套接字是異步的,所以它們都可以在同一個執行緒上運行。但是,服務器上的所有負載都分布在 1 個執行緒上,這似乎性能較低,因為它都在 1 個核心上運行。多執行緒上的異步服務器套接字?
將這些異步連接分布在所有可用內核上是否可能/有意義?例如,為每個內核創建一個執行緒,然后用異步任務均勻地填充這些執行緒?這樣,就有可能擁有“無限”的客戶端連接,并將負載分散到所有可用的核心上。uj5u.com熱心網友回復:
我們在 Hazelcast 中做什么:
有一個執行緒負責接受傳入的 TCP/IP 連接。
一旦 TCP/IP 連接被接受,它就會被分配給 I/O 執行緒陣列中的單個執行緒。因此,單個 TCP/IP 連接由單個 I/O 執行緒處理。
I/O 執行緒使用非阻塞 I/O,因此單個 I/O 執行緒可以同時服務多個 TCP/IP 連接。有關更多資訊,請參閱:https ://www.baeldung.com/java-nio-selector
這種設計可以通過去掉接受執行緒并通過將 SO_REUSEPORT 設定為 true 讓每個 I/O 執行緒也接受接受來簡化。這允許不同的行程在同一服務器埠上偵聽以接受請求。當建立 TCP/IP 連接時,作業系統將確定 TCP/IP 連接分配給哪個 I/O 執行緒。
您可能想看看 Reactor(也許還有 Proactor)設計模式。我上面描述的 I/O 執行緒可以看作是一個 Reactor。
uj5u.com熱心網友回復:
這在很大程度上是@markspace 答案的擴展,但更加關注原因。
如果您的問題是是否有可能確保每個請求都獲得一個唯一的核心并且被平均分配,是的,這是可能的,但是如果您將其作為實作要求,那么您就是在與語言斗爭以獲得要求遇見了。所以簡而言之,這是可能的,但不,這沒有意義。
Java 開發人員花費大量時間來正確地進行并發和任務調度,這意味著他們希望該工具成為一種多用途、一刀切的工具。顯然,并非每個工具都適合這項作業,但目標是限制您需要花費多少精力來調整工具以使其適合作業。如果您關心的是吞吐量,那么避免嘗試在某個方向上強制資源分配可能對您有利,而只是在需要時請求資源。讓 Java 專注于有效地做到這一點。
在 java 中,你也可以手動分配記憶體,很像 C 或 Rust。是的,這是可能的,但 java 的全部意義在于通過垃圾收集器從你那里抽象出所有這些資訊,這樣你就少了一個需要解決的問題。更具體地說,這個問題目前以比我們絕大多數人能夠做到的更好的方式得到解決。
但回到你原來的問題。無論如何,如果你認為你可以比作業系統(或 JVM,當 Loom 出現時)更好地執行任務調度和執行緒管理,那就繼續吧。但是,除非您對如何做到這一點有一個非常好的想法(或一個非常好的理由),否則這可能是不明智的,更不用說值得付出努力了。當前的實作足以滿足您職業生涯中 99% 的作業。
當然,如果這只是為了學習一些東西(而不是為了一個正在部署到 PROD 的系統),那么請一頭扎進——這里是大多數 Java 并發和異步邏輯的 repo。
https://github.com/openjdk/jdk/tree/master/src/java.base/share/classes/java/util/concurrent
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/462300.html
上一篇:任務延遲是否創建新執行緒?
