国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

BIO到NIO、多路復(fù)用器, 從理論到實(shí)踐, 結(jié)合實(shí)際案例對(duì)比各自效率與特點(diǎn)(下)

這篇具有很好參考價(jià)值的文章主要介紹了BIO到NIO、多路復(fù)用器, 從理論到實(shí)踐, 結(jié)合實(shí)際案例對(duì)比各自效率與特點(diǎn)(下)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

本篇文章是BIO到NIO、多路復(fù)用器, 從理論到實(shí)踐, 結(jié)合實(shí)際案例對(duì)比各自效率與特點(diǎn)(上)的下一篇, 如果沒(méi)有看的小伙伴, 可以先看下, 不然可能會(huì)不連貫.

多路復(fù)用器簡(jiǎn)介

多路復(fù)用器是對(duì)于傳統(tǒng)NIO的優(yōu)化, 解決了傳統(tǒng)NIO無(wú)法直接獲取所有所有連接的狀態(tài), 需要挨個(gè)遍歷所有連接查看是否準(zhǔn)備就緒的問(wèn)題, 這種方式會(huì)涉及到很多次系統(tǒng)調(diào)用, 用戶(hù)態(tài)和內(nèi)核態(tài)的切換,效率不高.

那多路復(fù)用器是怎樣優(yōu)化的呢?
首先要明白 多路的路是誰(shuí)-------->其實(shí)就是每個(gè)IO連接

每個(gè)路有沒(méi)有數(shù)據(jù)誰(shuí)知道呢-------->內(nèi)核知道, 那既然內(nèi)核自己知道某一時(shí)刻有哪些連接是有連接的, 是不是我們直接調(diào)用對(duì)應(yīng)功能方法即可, 所以這里就有個(gè)多路復(fù)用器, 你調(diào)用這個(gè)多路復(fù)用器, 它就會(huì)給你返回所有的路的IO狀態(tài).

這個(gè)就可以通過(guò)一次系統(tǒng)調(diào)用,獲取所有連接的IO狀態(tài)的結(jié)果集
然后程序自己對(duì)有狀態(tài)的(準(zhǔn)備好的)連接進(jìn)行讀寫(xiě),這樣才是高性能

這里注意,多說(shuō)一句, 只要程序自己讀寫(xiě)數(shù)據(jù), 你的IO模型就是同步的
BIO到NIO、多路復(fù)用器, 從理論到實(shí)踐, 結(jié)合實(shí)際案例對(duì)比各自效率與特點(diǎn)(下),計(jì)算機(jī)網(wǎng)絡(luò),nio,java,數(shù)據(jù)庫(kù)

多路復(fù)用器的兩個(gè)階段

多路復(fù)用器有兩個(gè)階段, 或者說(shuō)是內(nèi)核的兩類(lèi)實(shí)現(xiàn), 這兩類(lèi)實(shí)現(xiàn)的最終目的都是一樣的, 就是幫你返回所有IO連接的IO狀態(tài)(是否可讀), 但是實(shí)現(xiàn)細(xì)節(jié)有些許差別, 可以理解為epoll是select poll的升級(jí)版.

這里還是再提示下, 以下的兩種實(shí)現(xiàn)講的操作系統(tǒng)中的實(shí)現(xiàn), 并不是Java中的方法.

  • select poll
    需要把所有IO連接存到一個(gè)集合中, 把這個(gè)集合傳遞拷貝給內(nèi)核, 也就是調(diào)用select或者poll, 內(nèi)核會(huì)把集合中準(zhǔn)備就緒的連接給個(gè)特殊標(biāo)識(shí), 然后返回.
    這樣程序就可以直接知道哪些連接是有狀態(tài)的, 從而直接進(jìn)行讀取數(shù)據(jù)
    弊端:
    假如有1w個(gè)連接, 每次都需要把這個(gè)1w個(gè)連接拷貝給內(nèi)核, 這個(gè)拷貝就是損耗點(diǎn), 每次需要重復(fù)拷貝數(shù)據(jù)給內(nèi)核.

  • epoll
    正是因?yàn)閟elect, poll 有自身的弊端, 這才催生了epoll.
    優(yōu)化
    以空間換時(shí)間, 開(kāi)辟了內(nèi)核空間, 緩存了應(yīng)用程序的連接信息. 這樣就不需要重復(fù)的拷貝數(shù)據(jù).無(wú)損耗才是高性能.

    實(shí)現(xiàn)步驟
    1. 在一個(gè)linux機(jī)器上, 有很多的應(yīng)用程序, 所以一個(gè)應(yīng)用程序想要使用epoll的話(huà), 首先需要在內(nèi)核中 開(kāi)辟空間------對(duì)應(yīng)epoll_create系統(tǒng)調(diào)用
    2. 然后當(dāng)連接創(chuàng)建后, 把這個(gè)連接加入到該空間------對(duì)應(yīng)epoll_ctl(add)系統(tǒng)調(diào)用
    3. 然后才是進(jìn)行詢(xún)問(wèn), 看看有哪些IO連接準(zhǔn)備就緒------對(duì)應(yīng)epoll_wait系統(tǒng)調(diào)用

Java中的多路復(fù)用器封裝

在java.nio的包下,封裝了對(duì)于多路復(fù)用的實(shí)習(xí)和使用,也就是Selector類(lèi)

Java中的Seletor底層用的是哪種實(shí)現(xiàn)? select poll 還是epoll?
Java其實(shí)會(huì)在運(yùn)行的時(shí)候會(huì)動(dòng)態(tài)的決定使用哪種實(shí)現(xiàn), 因?yàn)樗鼤?huì)調(diào)用固定的方法去啟動(dòng)多路復(fù)用器,即Selector.open, 你的程序可能跑在不同的內(nèi)核之上, jdk會(huì)優(yōu)先選擇好的epoll, 但是如果沒(méi)有epoll這個(gè)多路復(fù)用器的話(huà),只有select或者poll, 也是可以正常運(yùn)行的

主要使用方法介紹:
這里有三個(gè)主要的方法, 不管底層使用的是哪種實(shí)現(xiàn), 都會(huì)調(diào)用這三個(gè)方法, 但是根據(jù)不同實(shí)現(xiàn), 具體做的事情又不一樣,區(qū)別如下:

  1. Selector.open
    啟動(dòng)多路復(fù)用器, 優(yōu)先選擇epoll, 沒(méi)有的話(huà)選擇select或者poll.
    如果是epoll的話(huà), 需要在內(nèi)核中開(kāi)辟空間, 即調(diào)用epoll_create.
  2. register
    select、poll: 會(huì)在jvm里建一個(gè)數(shù)組, 把每個(gè)連接對(duì)應(yīng)的文件描述符(fd4)都放進(jìn)去.
    epoll: 則相當(dāng)于調(diào)用內(nèi)核方法epoll_ctl(add), 將該連接加入到內(nèi)核空間, 直接由內(nèi)核管理.
  3. select
    select、poll: 則會(huì)將jvm中的數(shù)組傳給內(nèi)核, 即調(diào)用select(fd4)或者poll(fd4)
    epoll: 相當(dāng)于直接調(diào)用內(nèi)核方法epol_wait, 直接詢(xún)問(wèn)內(nèi)核

測(cè)試代碼

服務(wù)端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @ClassName:     
 * @Description:(描述這個(gè)類(lèi)的作用)   
 * @author: 
 * @date:        
 *   
 */  
public class SelectorTest {

    private static ServerSocketChannel server=null;
    private static Selector selector;
    static int port=9090;
    static int count=5000;
    static long startTime;

    public static void initServer(){
        try {
            server = ServerSocketChannel.open();
            server.configureBlocking(false);
            server.bind(new InetSocketAddress(port));

            //這里會(huì)在編譯期間自動(dòng)選擇 多路復(fù)用器的 實(shí)現(xiàn)
            //可能為select poll 也可能為epoll
            selector = Selector.open();
            server.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        initServer();
        System.out.println("服務(wù)器啟動(dòng)了......");
        startTime = System.currentTimeMillis();
        try {
            flag:
            while (true){
                //select相當(dāng)于詢(xún)問(wèn)內(nèi)核有無(wú)數(shù)據(jù)可讀取 或者 有無(wú)連接可建立
                //里面?zhèn)魅氲膮?shù)是超時(shí)時(shí)間,傳入0代表阻塞,一直等待有人建立連接或發(fā)送數(shù)據(jù)
                //如果傳入的>0, 比如200, 則會(huì)最多等待200毫秒,有沒(méi)有都會(huì)返回一個(gè)結(jié)果
                while(selector.select(0)>0){
                    //從多路復(fù)用器中取出所有有效的key
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while(iterator.hasNext()){
                        SelectionKey key = iterator.next();
                        //獲取之后要進(jìn)行移除,否則會(huì)重復(fù)獲取
                        iterator.remove();
                        //有新連接可建立
                        if(key.isAcceptable()){
                            acceptHander(key);
                        //可以進(jìn)行讀取
                        }else if(key.isReadable()){
                            readHander(key);
                        }
                    }
                    if(count <= 0){
                        System.out.println("處理5000個(gè)連接用時(shí):"+(System.currentTimeMillis()-startTime)/1000+"s");
                        server.close();
                        selector.close();
                        break flag;
                    }
                }


            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private static void readHander(SelectionKey key) {
        //取出當(dāng)前key所關(guān)聯(lián)的客戶(hù)端
        SocketChannel client = (SocketChannel) key.channel();
        //取出該客戶(hù)端 對(duì)應(yīng)的  buffer
        //這個(gè)buffer是我們建立連接時(shí)傳進(jìn)去和 channel一對(duì)一綁定的
        ByteBuffer buffer = (ByteBuffer) key.attachment();

        buffer.clear();
        int read=0;
        try {
            for(;;){
                //從channel中讀取數(shù)據(jù)寫(xiě)入到buffer中
                read = client.read(buffer);
                if(read==0){
                    break;
                //這里可能有bug,客戶(hù)端可能關(guān)掉,處理close_wait狀態(tài), 會(huì)一直監(jiān)聽(tīng)到這個(gè)事件
                // 這里直接簡(jiǎn)單暴力的關(guān)掉
                }else if(read<0){
                    client.close();
                    break;
                }else{
                    //對(duì)于buffer,剛剛是寫(xiě),現(xiàn)在進(jìn)行讀操作,調(diào)用flip
                    buffer.flip();

                    byte[] bytes = new byte[buffer.limit()];
                    buffer.get(bytes);

                    String str = new String(bytes);
                    System.out.println(client.socket().getRemoteSocketAddress()+" -->" +str);
                }

            }

        }catch (Exception e){
            e.printStackTrace();

        }


    }

    private static void acceptHander(SelectionKey key) {
        try {
            ServerSocketChannel channel = (ServerSocketChannel) key.channel();
            SocketChannel client = channel.accept();
            client.configureBlocking(false);
            ByteBuffer buffer = ByteBuffer.allocate(8192);
            //將這個(gè)新連接交給多路復(fù)用器去管理,后面多路復(fù)用器中才能監(jiān)控這個(gè)連接, 在我們?nèi)カ@取的時(shí)候,給我們返回有狀態(tài)的連接
            //同時(shí)這里將channel和buffer 一對(duì)一 進(jìn)行綁定,可以很方便的往里寫(xiě)入, 或者 讀出來(lái)
            client.register(selector, SelectionKey.OP_READ,buffer);
            System.out.println("add client port:"+client.socket().getPort());

            count--;


        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

測(cè)試使用的客戶(hù)端代碼還是和上篇文章中保持一致, 這里不再放了.

壓測(cè)結(jié)果

以上所有說(shuō)的都是理論, 而理論一定是需要實(shí)際結(jié)果來(lái)驗(yàn)證的, 我們這里就還是同樣處理5000個(gè)連接, 并接收同樣消息, 看看多路復(fù)用器的實(shí)際效果如何.
BIO到NIO、多路復(fù)用器, 從理論到實(shí)踐, 結(jié)合實(shí)際案例對(duì)比各自效率與特點(diǎn)(下),計(jì)算機(jī)網(wǎng)絡(luò),nio,java,數(shù)據(jù)庫(kù)

可以看到, 效果是非常非常明顯的, 比BIO,NIO都要快太多了, 而且還代碼還是單線(xiàn)程模型, 將其擴(kuò)展成多線(xiàn)程, 效率將會(huì)更高.

總結(jié)

從BIO -> NIO -> 多路復(fù)用器, 我們分析了各自的缺點(diǎn)及演變過(guò)程, 并是實(shí)際結(jié)果對(duì)比了各自的效率, 相信你會(huì)更加印象深刻.

針對(duì)本文的測(cè)試結(jié)果總結(jié)如下:

BIO到NIO、多路復(fù)用器, 從理論到實(shí)踐, 結(jié)合實(shí)際案例對(duì)比各自效率與特點(diǎn)(下),計(jì)算機(jī)網(wǎng)絡(luò),nio,java,數(shù)據(jù)庫(kù)

今天的分享就到這里了,有問(wèn)題可以在評(píng)論區(qū)留言,均會(huì)及時(shí)回復(fù)呀.
我是bling,未來(lái)不會(huì)太差,只要我們不要太懶就行, 咱們下期見(jiàn).
BIO到NIO、多路復(fù)用器, 從理論到實(shí)踐, 結(jié)合實(shí)際案例對(duì)比各自效率與特點(diǎn)(下),計(jì)算機(jī)網(wǎng)絡(luò),nio,java,數(shù)據(jù)庫(kù)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-690022.html

到了這里,關(guān)于BIO到NIO、多路復(fù)用器, 從理論到實(shí)踐, 結(jié)合實(shí)際案例對(duì)比各自效率與特點(diǎn)(下)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀(guān)點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 阻塞非阻塞IO(BIO和NIO),IO多路復(fù)用

    阻塞非阻塞IO(BIO和NIO),IO多路復(fù)用

    1.概念 NIO(New Input/Output)和BIO(Blocking Input/Output)是Java中用于處理輸入輸出的兩種不同的模型。 ? BIO 會(huì) 阻塞 ,等有了消息,立刻返回,一個(gè)線(xiàn)程處理一個(gè)recv(需要很多線(xiàn)程)。 NIO 有沒(méi)有消息,都返回(但程序要自己判斷,返回空就循環(huán)重復(fù));一個(gè)線(xiàn)程可以處理多個(gè)

    2024年02月09日
    瀏覽(21)
  • 從Java BIO到NIO再到多路復(fù)用,看這篇就夠了

    從Java BIO到NIO再到多路復(fù)用,看這篇就夠了

    目錄 從一次優(yōu)化說(shuō)起 IO模型分類(lèi) 分類(lèi) 舉例 概念詳解 阻塞和非阻塞 同步與異步 Java支持版本 實(shí)戰(zhàn) c10k問(wèn)題 上代碼 BIO服務(wù)端 NIO服務(wù)端??????? 多路復(fù)用 概念 階段一:selectpoll 階段二epoll Java selector 后記 ????????近期優(yōu)化了一個(gè)老的網(wǎng)關(guān)系統(tǒng),在dubbo調(diào)用接口rt100

    2024年02月08日
    瀏覽(18)
  • AI計(jì)算中的光學(xué)模塊:波分復(fù)用器的應(yīng)用前景

    AI計(jì)算中的光學(xué)模塊:波分復(fù)用器的應(yīng)用前景

    在人工智能(AI)的計(jì)算領(lǐng)域,光學(xué)模塊扮演著至關(guān)重要的角色。隨著AI技術(shù)的飛速發(fā)展,對(duì)數(shù)據(jù)處理速度和帶寬的需求日益增長(zhǎng)。光學(xué)模塊,特別是波分復(fù)用器(WDM),因其高速、大容量的數(shù)據(jù)傳輸能力而成為研究和應(yīng)用的熱點(diǎn)。 ADOP-DWDM40路波分 一、波分復(fù)用器在A(yíng)I計(jì)算中的

    2024年04月29日
    瀏覽(11)
  • IO、NIO、IO多路復(fù)用

    IO、NIO、IO多路復(fù)用

    IO是什么? 網(wǎng)絡(luò)IO是如何連接的? 下面是一次網(wǎng)絡(luò)讀取內(nèi)容的I/O示意圖,數(shù)據(jù)先從外設(shè)(網(wǎng)卡)到內(nèi)核空間,再到用戶(hù)空間(JVM),最后到應(yīng)用程序的一個(gè)過(guò)程。 上述一次I/O讀取,所謂的阻塞和非阻塞體現(xiàn)在哪里呢? Java最早期的版本的I/O就是這樣實(shí)現(xiàn)的。當(dāng)程序調(diào)用到讀取

    2024年01月20日
    瀏覽(32)
  • Java NIO原理 (Selector、Channel、Buffer、零拷貝、IO多路復(fù)用)

    Java NIO原理 (Selector、Channel、Buffer、零拷貝、IO多路復(fù)用)

    系列文章目錄和關(guān)于我 最近有很多想學(xué)的,像netty的使用、原理源碼,但是苦于自己對(duì)于操作系統(tǒng)和nio了解不多,有點(diǎn)無(wú)從下手,遂學(xué)習(xí)之。 上圖粗略描述了網(wǎng)絡(luò)io的過(guò)程,了解其中的拷貝過(guò)程有利于我們理解非阻塞io,以及IO多路復(fù)用的必要性。 數(shù)據(jù)從網(wǎng)卡到內(nèi)核緩沖區(qū) 網(wǎng)

    2024年02月08日
    瀏覽(21)
  • BIO、NIO線(xiàn)程模型

    BIO(Blocking IO): 同步阻塞模型,一個(gè)客戶(hù)端連接對(duì)應(yīng)一個(gè)處理線(xiàn)程,即:一個(gè)線(xiàn)程處理一個(gè)客戶(hù)端請(qǐng)求。 ? ? 單線(xiàn)程版本: 服務(wù)端在處理完第一個(gè)客戶(hù)端的所有事件之前,無(wú)法為其他客戶(hù)端提供服務(wù)。 ? ? 多線(xiàn)程版本:如果出現(xiàn)大量只連接不發(fā)數(shù)據(jù)的話(huà),那么就會(huì)一直占用

    2024年02月09日
    瀏覽(20)
  • NIO與BIO

    當(dāng)談到 Java 網(wǎng)絡(luò)編程時(shí),經(jīng)常會(huì)聽(tīng)到兩個(gè)重要的概念:BIO(Blocking I/O,阻塞 I/O)和 NIO(Non-blocking I/O,非阻塞 I/O)。它們都是 Java 中用于處理 I/O 操作的不同編程模型。 BIO 是 Java 最早的 I/O 模型,也是最簡(jiǎn)單的一種。在 BIO 模型中,每個(gè) I/O 操作都會(huì)阻塞當(dāng)前線(xiàn)程,直到數(shù)據(jù)

    2024年04月10日
    瀏覽(19)
  • 33. bio和nio

    33. bio和nio

    1.1 bio網(wǎng)絡(luò)模型示意圖 單個(gè)客戶(hù)端向服務(wù)器發(fā)起請(qǐng)求時(shí),請(qǐng)求順序如下: 多個(gè)客戶(hù)端向一個(gè)服務(wù)器發(fā)起請(qǐng)求時(shí),請(qǐng)求順序如下: 1.2 bio網(wǎng)絡(luò)模型缺點(diǎn) 1.阻塞式I/O 2.彈性伸縮能力差 3.多線(xiàn)程耗費(fèi)資源 2.1 nio網(wǎng)絡(luò)模型示意圖 單個(gè)客戶(hù)端向服務(wù)器發(fā)起請(qǐng)求時(shí),請(qǐng)求順序如下: 2.2 ni

    2024年02月17日
    瀏覽(20)
  • BIO、NIO和AIO

    BIO、NIO和AIO

    目錄 一.引言 何為IO IO的過(guò)程 Java的3種網(wǎng)絡(luò)IO模型 阻塞和非阻塞IO IO多路復(fù)用 異步和同步IO 二.BIO 三.NIO 1. 三大組件 Channel Buffer Selector 2.ByteBuffer 2.1ByteBuffer的使用 2.2ByteBuffer 結(jié)構(gòu) ?2.3ByteBuffer的常用方法 分配空間 ? 向 buffer 寫(xiě)入數(shù)據(jù) 從 buffer 讀取數(shù)據(jù) 字符串與 ByteBuffer 互轉(zhuǎn) 分

    2024年02月12日
    瀏覽(23)
  • BIO、NIO、AIO區(qū)別詳解

    主線(xiàn)程發(fā)起io請(qǐng)求后,需要等待當(dāng)前io操作完成,才能繼續(xù)執(zhí)行。 引入selector、channel、等概念,當(dāng)主線(xiàn)程發(fā)起io請(qǐng)求后,輪詢(xún)的查看系統(tǒng)是否準(zhǔn)備好執(zhí)行io操作,沒(méi)有準(zhǔn)備好則主線(xiàn)程不會(huì)阻塞會(huì)繼續(xù)執(zhí)行,準(zhǔn)備好主線(xiàn)程會(huì)阻塞等待io操作完成。 主線(xiàn)程發(fā)起io請(qǐng)求后,不會(huì)阻塞,

    2024年02月07日
    瀏覽(29)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包