<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 網絡IO模型變化 涉及到網絡模型有如下幾個名稱概念: `同步、異步、阻塞、非阻塞`。 - 同步:應用程序自己完成讀寫操作。 - 異步:內核完成讀寫操作,就好像程序沒有訪問IO,而是直接訪問了內核緩沖區。 - 阻塞:調用阻塞方法時一定會拿到返回值。 - 非阻塞:調用非阻塞方法時可能拿不到返回值。 由這些可以組成多種不同的網絡模型: - 同步阻塞:BIO - 同步非阻塞:NIO、多路復用 - 異步非阻塞:AIO - 異步阻塞:沒有意義! 使用命令: ~~~ strace -off -o out cmd ~~~ 可以用于最終每個線程的系統調用情況,輸出為out文件。 &nbsp; C10K問題: 單機是否能夠支持1萬個鏈接? 下面對C10K問題進行性能壓測: &nbsp; ## BIO 代碼: ~~~ public static void main(String[] args) { ServerSocket server = null; try { server = new ServerSocket(); server.bind(new InetSocketAddress( 9090), BACK_LOG); server.setReceiveBufferSize(RECEIVE_BUFFER); } catch (IOException e) { e.printStackTrace(); } System.out.println("server up use 9090!"); while (true) { try { System.in.read(); //分水嶺: Socket client = server.accept(); System.out.println("client port: " + client.getPort()); new Thread( () -> { while (true) { try { InputStream in = client.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); char[] data = new char[1024]; int num = reader.read(data); if (num > 0) { System.out.println("client read some data is :" + num + " val :" + new String(data, 0, num)); } else if (num == 0) { System.out.println("client readed nothing!"); continue; } else { System.out.println("client readed -1..."); client.close(); break; } } catch (IOException e) { e.printStackTrace(); } } } ).start(); } catch (IOException e) { e.printStackTrace(); }finally { try { server.close(); } catch (IOException e) { e.printStackTrace(); } } } } ~~~ 在上面服務端的代碼在運行過程中,while死循環一直在等待連接,當發生accept(系統調用)方法時,每次都新建了一個線程進行處理,同時操作內核會克隆一個內核級的線程。當然可以采用池化的技術增加線程的利用率。這也是BIO慢的原因。整個BIO的弊端就是因為accept、read、write阻塞,而且這個阻塞還是因為內核提供的API是阻塞的才會造成的。 &nbsp; ## NIO NIO有兩個含義:一個是在java.nio包中表示new IO;一個是在操作系統中表示NONBlocking,非阻塞的意思。 ~~~ List<SockerChannel> list = new ArrayList<>(); ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 設置為非阻塞 while (true) { accept(); if == null for (SocketChannel c : list) { .. 處理讀寫 } } ~~~ 假設采用11萬連接的客戶端去進行壓測,會=發現建立連接的速度為BIO快很多。但是發現到后面越來越慢了,因為每次List的遍歷的次數會越來越多。最后可能出現如下問題`Too many open files`的問題。 NIO的優勢: 1. 通過一個或者多個的線程,來解決N個客戶端的連接處理。 NIO的問題: 1. 雖然是單線程的,但是每次循環都需要O(n)的系統調用的成本,詢問是否有數據。但是實際場景中真的有數據的連接并不多,所以有很多系統調用是浪費的。系統調用accept、recv等都需要做保護現場等工作,比較費時。注意并不是服務端代碼調用read系統調用的問題,而是很多read系統調用沒有數據的問題。 &nbsp; ## 多路復用器 多路復用器指的是多個客戶端復用一次系統調用,只用一次系統調用就能知道各個連接的IO狀態,進程由程序進一步控制對有狀態的IO進行讀寫操作。 Linux中提供了三種多路復用器:**select、poll、epoll**。Java中的Selector.open會根據不同的操作系統選擇不同的多路復用器,可以在虛擬機參數中進行配置,在Linux系統中默認是調用epoll。 其實無論是NIO還是多路復用,都是需要遍歷所有的IO詢問到狀態的。只不過NIO的這個遍歷**每次**都需要用戶態到內核態的切換,而多路復用器的遍歷過程只觸發了**一次**用戶態到內核態的系統調用,把很多的fd傳遞給內核,內核遍歷這些fd,并修改狀態,之后返回給用戶態,用戶態再根據這些問題具體處理。 **多路復用器也是運行在同步非阻塞模型!!!異步Linux還不完善。** &nbsp; ### select方法 Linux系統中最早的一個多路復用器、其能夠接收的文件描述符有限制,受參數FD_SETSIZE的限制,為1024。 select方法每次在發生系統調用的時候,會復制一份所有的文件描述符fds,傳遞給內核,內核遍歷fds后修改狀態后返回給用戶態。用戶態再次遍歷fds,然后處理有狀態的fd。可以發現這個過程雖然只有一次系統調用,但是需要2次的全量遍歷fds的過程。 &nbsp; ### poll方法 poll方法是對select的優化,與select的主要區別是沒有FD_SETSIZE的限制,兩者的工作模式比較像。 &nbsp; ### epoll方法 最新的一個多路復用器,也是使用得最多的一個多路復用器。 包括三個過程: 1. epoll\_create:創建一個新的epoll實例,并返回一個文件描述符指向這個epoll實例。即在內核中開辟一塊空間,并返回一個fd指向該內核空間。這塊空間里存放了一顆紅黑樹,也稱為epoll\_fd。 2. epoll\_ctl:可以看成是控制epoll\_fd這塊區域的操作,例如往里面添加fd或者刪除fd。 3. epoll\_wait:epoll\_wait在等待一個鏈表,這個鏈表中的是由紅黑樹中發生事件的節點遷移過去的,由中斷進行處理。如果沒有事件的會阻塞線程進行等待。 因此每次在系統調用的時候拿到鏈表即可,鏈表中的節點都表示有狀態的節點,因此不用全量的遍歷整個fds。 &nbsp; ## Reactor模式 對多路復用的一層封裝,表示對應事件的意思,當有一個事件來的時候,Reactor就會對其作出反應。Reactor模式也叫作**Disapatcher**分發模式,I/O 多路復?監 聽事件,收到事件后,根據事件類型分配(Dispatch)給某個進程 / 線程進行處理。例如Netty中的EventLoopGroup。其中: - Reactor 負責監聽和分發事件,事件類型包含連接事件、讀寫事件; - 處理資源池負責處理事件,如 read -> 業務邏輯 -> send。 **可能理解成Boss和Worker會比較好理解一點。** Reactor一般可以分為如下幾種: - 單個Reactor,單工作線程: :-: ![](https://img.kancloud.cn/63/1e/631e9ab19348af8dfd17400ec7cf27f9_963x577.png) - 單個Reactor,多個工作線程: :-: ![](https://img.kancloud.cn/f3/12/f312ec4f326f8089eab5eb860e19cd92_923x777.png) - 多個Reactor,多個工作線程: :-: ![](https://img.kancloud.cn/b1/3b/b13bdd7e09a8427b5043aa9cae413d3f_994x722.png) **Netty就是使用這種。**
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看