最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis IO多路復用模型使用及說明

 更新時間:2026年03月24日 09:54:35   作者:我學學學學學學學  
這篇文章主要介紹了Redis IO多路復用模型使用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

Redis單線程是如何處理那么多并發(fā)客戶端連接?為什么單線?為什么那么快?

這是因為Redis使用了IO多路復用,Redis利用epoll來實現(xiàn)IO多路復用,將連接信息和事件放到隊列中,一次放到文件事件分派器,事件分派器將事件分發(fā)給事件處理器。

我們一般面試中都會這樣回答,那么什么是IO多路復用模型?epoll又是什么?首先我們先來了解一下UNIX網(wǎng)絡編程的五種IO模型。

UNIX網(wǎng)絡編程的五種IO模型

1、Blocking IO:阻塞IO;

2、NoneBlocking IO: 非阻塞IO;

3、IO multiplexing:IO多路復用;

4、signal driven IO:信號驅動IO(略);

5、asynchronous IO:異步IO(略)。

同步和異步

同步:調(diào)用者要一直等待調(diào)用結果的通知后才能進行后續(xù)的執(zhí)行?,F(xiàn)在就要,我可以等,等到結果為止。

異步:指被調(diào)用方先返回應答讓調(diào)用者先回去,然后再計算調(diào)用結果,計算完最終結果再通知并返回給調(diào)用方。異步調(diào)用想要獲取結果一般通過回調(diào)。

同步、異步的討論對象是被調(diào)用者(服務提供者),重點在于獲得調(diào)用結果的消息通知方式上。

阻塞和非阻塞

阻塞:調(diào)用方一直在等待且別的事情什么都不做,當前線 / 進程會被掛起,啥也不干。

非阻塞:調(diào)用在發(fā)出去后,調(diào)用方先去做別的事情,不會阻塞當前線 / 進程,而會立刻返回。

阻塞和非阻塞討論的對象是調(diào)用者(服務請求者),重點在于等消息時候的行為,調(diào)用者是否能干其他事。

4種組合方式

同步阻塞、同步非阻塞、異步阻塞、異步非阻塞。

同步阻塞:服務員說快到你了,先別離開我后臺看一眼馬上通知你。客戶在海底撈前臺干等,啥也不干。

同步非阻塞:服務員說快到你了,先別離開??蛻粼诤5讚魄芭_邊刷抖音邊等叫號。

異步阻塞:服務員說還需要等位,你先去逛逛,一會通知你??蛻襞逻^號在海底撈前臺拿著排號小票啥也不干,就在那等著店員通知。

異步非阻塞:服務員說還需要等位,你先去逛逛,一會通知你。拿著排號小票,刷著抖音,等著店員通知。

BIO

在阻塞式I/O模型中,應用程序在從調(diào)用rercvfrom開始到他返回有數(shù)據(jù)報準備好這段時間是阻塞的,recvfrom返回成功后,應用進程才能開始處理數(shù)據(jù)報。tomcat7之前就是用BIO多線程來解決多連接。

accept監(jiān)聽

public class RedisClient01
{
    public static void main(String[] args) throws IOException
    {
        System.out.println("------RedisClient01 start");
        Socket socket = new Socket("127.0.0.1", 6379);
        System.out.println("------RedisClient01 connection over");
    }
}
public class RedisClient02
{
    public static void main(String[] args) throws IOException
    {
        System.out.println("------RedisClient02 start");
        Socket socket = new Socket("127.0.0.1", 6379);
        System.out.println("------RedisClient02 connection over");
    }
}
public class RedisServer
{
    public static void main(String[] args) throws IOException
    {
        ServerSocket serverSocket = new ServerSocket(6379);

        while(true)
        {
            System.out.println("模擬RedisServer啟動-----111 等待連接");
            Socket socket = serverSocket.accept();
            System.out.println("-----222 成功連接:  "+ IdUtil.simpleUUID());
            System.out.println();
        }
    }
}

啟動RedisServer,并啟動RedisClient01,RedisClient02。

read讀取

public class RedisClient01
{
    public static void main(String[] args) throws IOException
    {
        Socket socket = new Socket("127.0.0.1",6379);
        OutputStream outputStream = socket.getOutputStream();

        while(true)
        {
            Scanner scanner = new Scanner(System.in);
            String string = scanner.next();
            if (string.equalsIgnoreCase("quit")) {
                break;
            }
            socket.getOutputStream().write(string.getBytes());
            System.out.println("------RedisClient01 input quit keyword to finish......");
        }
        outputStream.close();
        socket.close();
    }
}
public class RedisClient02
{
    public static void main(String[] args) throws IOException
    {
        Socket socket = new Socket("127.0.0.1",6379);
        OutputStream outputStream = socket.getOutputStream();

        while(true)
        {
            Scanner scanner = new Scanner(System.in);
            String string = scanner.next();
            if (string.equalsIgnoreCase("quit")) {
                break;
            }
            socket.getOutputStream().write(string.getBytes());
            System.out.println("------RedisClient02 input quit keyword to finish......");
        }
        outputStream.close();
        socket.close();
    }
}
public class RedisServerBIO
{
    public static void main(String[] args) throws IOException
    {
        ServerSocket serverSocket = new ServerSocket(6379);

        while(true)
        {
            System.out.println("-----111 等待連接");
            Socket socket = serverSocket.accept();//阻塞1 ,等待客戶端連接
            System.out.println("-----222 成功連接");

            InputStream inputStream = socket.getInputStream();
            int length = -1;
            byte[] bytes = new byte[1024];
            System.out.println("-----333 等待讀取");
            while((length = inputStream.read(bytes)) != -1)//阻塞2 ,等待客戶端發(fā)送數(shù)據(jù)
            {
                System.out.println("-----444 成功讀取"+new String(bytes,0,length));
                System.out.println("===================="+"\t"+ IdUtil.simpleUUID());
                System.out.println();
            }
            inputStream.close();
            socket.close();
        }
    }
}

啟動RedisServerBIO,并啟動RedisClient01發(fā)送消息。

成功讀取1號連接發(fā)送的消息,啟動RedisClient02發(fā)送消息。

發(fā)現(xiàn)并沒有接收到2號連接發(fā)送的消息,這時我們退出1號連接。

成功接收到2號連接發(fā)送的消息。

上面的模型存在很大的問題,如果客戶端與服務端建立了連接,如果這個連接的客戶端遲遲不發(fā)數(shù)據(jù),程就會一直堵塞在read()方法上,這樣其他客戶端也不能進行連接,也就是一次只能處理一個客戶端,對客戶很不友好。

可以利用多線程。只要連接了一個socket,操作系統(tǒng)分配一個線程來處理,這樣read()方法堵塞在每個具體線程上而不堵塞主線程,就能操作多個socket了,哪個線程中的socket有數(shù)據(jù),就讀那個。socket,各取所需,靈活統(tǒng)一。程序服務端只負責監(jiān)聽是否有客戶端連接,使用 accept() 阻塞。客戶端1連接服務端,就開辟一個線程(thread1)來執(zhí)行 read() 方法,程序服務端繼續(xù)監(jiān)聽??蛻舳?連接服務端,也開辟一個線程(thread2)來執(zhí)行 read() 方法,程序服務端繼續(xù)監(jiān)聽??蛻舳?連接服務端,也開辟一個線程(thread3)來執(zhí)行 read() 方法,程序服務端繼續(xù)監(jiān)聽任何一個線程上的socket有數(shù)據(jù)發(fā)送過來,read()就能立馬讀到,cpu就能進行處理。

改造代碼:

public class RedisServerBIOMultiThread
{
    public static void main(String[] args) throws IOException
    {
        ServerSocket serverSocket = new ServerSocket(6379);

        while(true)
        {
            System.out.println("-----RedisServerBIOMultiThread 111 等待連接");
            Socket socket = serverSocket.accept();//阻塞1 ,等待客戶端連接
            System.out.println("-----RedisServerBIOMultiThread 222 成功連接");

            new Thread(() -> {
                try {
                    InputStream inputStream = socket.getInputStream();
                    int length = -1;
                    byte[] bytes = new byte[1024];
                    System.out.println("-----333 等待讀取"+ IdUtil.simpleUUID());
                    while((length = inputStream.read(bytes)) != -1)//阻塞2 ,等待客戶端發(fā)送數(shù)據(jù)
                    {
                        System.out.println("-----444 成功讀取"+new String(bytes,0,length));
                        System.out.println("====================");
                        System.out.println();
                    }
                    inputStream.close();
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            },Thread.currentThread().getName()).start();

            new Thread().start();

        }
    }
}

啟動RedisServerBIOMultiThread,并啟動RedisClient01,RedisClient02發(fā)送消息。

成功接收1號連接2號連接發(fā)送的消息,那么現(xiàn)在的BIO多線程模型還有什么問題嗎?

多線程模型:每來一個客戶端,就要開辟一個線程,如果來1萬個客戶端,那就要開辟1萬個線程。在操作系統(tǒng)中用戶態(tài)不能直接開辟線程,需要調(diào)用內(nèi)核來創(chuàng)建的一個線程,這其中還涉及到用戶狀態(tài)的切換(上下文的切換),十分耗資源。

解決方法:

第一個辦法:使用線程池。這個在客戶端連接少的情況下可以使用,但是用戶量大的情況下,你不知道線程池要多大,太大了內(nèi)存可能不夠,也不可行。

第二個辦法:NIO(非阻塞式IO)方式。因為read()方法堵塞了,所有要開辟多個線程,如果什么方法能使read()方法不堵塞,這樣就不用開辟多個線程了,這就用到了另一個IO模型,NIO(非阻塞式IO)。

NIO

在NIO模式中,一切都是非阻塞的:accept()方法是非阻塞的,如果沒有客戶端連接,就返回無連接標識。read()方法是非阻塞的,如果read()方法讀取不到數(shù)據(jù)就返回空閑中標識,如果讀取到數(shù)據(jù)時只阻塞read()方法讀數(shù)據(jù)的時間。在NIO模式中,只有一個線程:當一個客戶端與服務端進行連接,這個socket就會加入到一個數(shù)組中,隔一段時間遍歷一次,看這個socket的read()方法能否讀到數(shù)據(jù),這樣一個線程就能處理多個客戶端的連接和讀取了。

public class RedisServerNIO
{
    static ArrayList<SocketChannel> socketList = new ArrayList<>();
    static ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

    public static void main(String[] args) throws IOException
    {
        System.out.println("---------RedisServerNIO 啟動等待中......");
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress("127.0.0.1",6379));
        serverSocket.configureBlocking(false);//設置為非阻塞模式

        while (true) {
            for (SocketChannel element : socketList) {
                int read = element.read(byteBuffer);
                if(read > 0)
                {
                    System.out.println("-----讀取數(shù)據(jù): "+read);
                    byteBuffer.flip();
                    byte[] bytes = new byte[read];
                    byteBuffer.get(bytes);
                    System.out.println(new String(bytes));
                    byteBuffer.clear();
                }
            }
            SocketChannel socketChannel = serverSocket.accept();
            if(socketChannel != null) {
                System.out.println("-----成功連接: ");
                socketChannel.configureBlocking(false);//設置為非阻塞模式
                socketList.add(socketChannel);
                System.out.println("-----socketList size: "+socketList.size());
            }
        }
    }
}

啟動RedisServerNIO,并啟動RedisClient01,RedisClient02發(fā)送消息。

成功接收1號連接2號連接發(fā)送的消息,但是如何用單線程處理大量的連接呢?

IO多路復用模型

I/O多路復用在英文中其實叫 I/O multiplexing 。多個Socket復用一根網(wǎng)線這個功能是在內(nèi)核+驅動層實現(xiàn)的。I/O multiplexing 這里面的 multiplexing 指的其實是在單個線程通過記錄跟蹤每一個Sock(I/O流)的狀態(tài)來同時管理多個I/O流. 目的是盡量多的提高服務器的吞吐能力。大家都用過nginx,nginx使用epoll接收請求,ngnix會有很多鏈接進來, epoll會把他們都監(jiān)視起來,然后像撥開關一樣,誰有數(shù)據(jù)就撥向誰,然后調(diào)用相應的代碼處理。redis類似同理。

I/O:網(wǎng)絡I/O。

多路:多個客戶端連接(連接就是套接字描述符,即 socket 或者 channel) ,指的是多條 TCP 連接復用: 用一個進程來處理多條的連接,使用單進程就能夠實現(xiàn)同時處理多個客戶端的連接實現(xiàn)了用一個進程來處理大量的用戶連接。

IO multiplexing就是我們說的select,poll,epoll,有些技術書籍也稱這種IO方式為event driven IO事件驅動IO。就是通過一種機制,一個進程可以監(jiān)視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作。可以基于一個阻塞對象并同時在多個描述符上等待就緒,而不是使用多個線程(每個文件描述符一個線程,每次new一個線程),這樣可以大大節(jié)省系統(tǒng)資源。所以,I/O 多路復用的特點是通過一種機制一個進程能同時等待多個文件描述符而這些文件描述符(套接字描述符)其中的任意一個進入讀就緒狀態(tài),select,poll,epoll等函數(shù)就可以返回。

文件描述符

文件描述符(File descriptor)計算機科學中的一個術語,是一個用于表述指向文件的引用的抽象化概念。文件描述符在形式上是一個非負整數(shù)。實際上,它是一個索引值,指向內(nèi)核為每一個進程所維護的該進程打開文件的記錄表。當程序打開一個現(xiàn)有文件或者創(chuàng)建一個新文件時,內(nèi)核向進程返回一個文件描述符。在程序設計中,一些涉及底層的程序編寫往往會圍繞著文件描述符展開。但是文件描述符這一概念往往只適用于UNIX、Linux這樣的操作系統(tǒng)。

舉例描述IO多路復用模型

模擬一個tcp服務器處理30個客戶socket,一個監(jiān)考老師監(jiān)考多個學生,誰舉手就應答誰。假設你是一個監(jiān)考老師,讓30個學生解答一道競賽考題,然后負責驗收學生答卷,你有下面幾個選擇:

第一種選擇:按順序逐個驗收,先驗收A,然后是B,之后是C、D。。。這中間如果有一個學生卡住,全班都會被耽誤,你用循環(huán)挨個處理socket,根本不具有并發(fā)能力。 

第二種選擇:你創(chuàng)建30個分身線程,每個分身線程檢查一個學生的答案是否正確。 這種類似于為每一個用戶創(chuàng)建一個進程或者線程處理連接。

第三種選擇,你站在講臺上等,誰解答完誰舉手。這時C、D舉手,表示他們解答問題完畢,你下去依次檢查C、D的答案,然后繼續(xù)回到講臺上等。此時E、A又舉手,然后去處理E和A。這種就是IO復用模型。Linux下的select、poll和epoll就是干這個的。

將用戶socket對應的fd注冊進epoll,然后epoll幫你監(jiān)聽哪些socket上有消息到達,這樣就避免了大量的無用操作。此時的socket應該采用非阻塞模式。這樣,整個過程只在調(diào)用select、poll、epoll這些調(diào)用的時候才會阻塞,收發(fā)客戶消息是不會阻塞的,整個進程或者線程就被充分利用起來,這就是事件驅動,所謂的reactor反應模式。所謂 I/O 多路復用機制,就是說通過一種考試監(jiān)考機制,一個老師可以監(jiān)視多個考生,一旦某個考生舉手想要交卷了,能夠通知監(jiān)考老師進行相應的收卷子或批改檢查操作。所以這種機制需要調(diào)用班主任(select/poll/epoll)來配合。多個考生被同一個班主任監(jiān)考,收完一個考試的卷子再處理其它人,無需等待所有考生,誰先舉手就先響應誰,當又有考生舉手要交卷,監(jiān)考老師看到后從講臺走到考生位置,開始進行收卷處理。

Reactor設計模式

基于 I/O 復用模型:多個連接共用一個阻塞對象,應用程序只需要在一個阻塞對象上等待,無需阻塞等待所有連接。當某條連接有新的數(shù)據(jù)可以處理時,操作系統(tǒng)通知應用程序,線程從阻塞狀態(tài)返回,開始進行業(yè)務處理。Reactor 模式,是指通過一個或多個輸入同時傳遞給服務處理器的服務請求的事件驅動處理模式。服務端程序處理傳入多路請求,并將它們同步分派給請求對應的處理線程,Reactor 模式也叫 Dispatcher 模式。即 I/O 多了復用統(tǒng)一監(jiān)聽事件,收到事件后分發(fā)(Dispatch 給某進程),是編寫高性能網(wǎng)絡服務器的必備技術。

Reactor 模式中有 2 個關鍵組成:

1)Reactor:Reactor 在一個單獨的線程中運行,負責監(jiān)聽和分發(fā)事件,分發(fā)給適當?shù)奶幚沓绦騺韺?IO 事件做出反應。 它就像公司的電話接線員,它接聽來自客戶的電話并將線路轉移到適當?shù)穆?lián)系人;

2)Handlers:處理程序執(zhí)行 I/O 事件要完成的實際事件,類似于客戶想要與之交談的公司中的實際辦理人。Reactor 通過調(diào)度適當?shù)奶幚沓绦騺眄憫?I/O 事件,處理程序執(zhí)行非阻塞操作。

那么現(xiàn)在我們在再來看一下Redis單線程是如何處理那么多并發(fā)客戶端連接?為什么單線?為什么那么快?

Redis 是跑在單線程中的,所有的操作都是按照順序線性執(zhí)行的,但是由于讀寫操作等待用戶輸入或輸出都是阻塞的,所以 I/O 操作在一般情況下往往不能直接返回,這會導致某一文件的 I/O 阻塞導致整個進程無法對其它客戶提供服務,而 I/O 多路復用就是為了解決這個問題而出現(xiàn)。所謂 I/O 多路復用機制,就是說通過一種機制,可以監(jiān)視多個描述符,一旦某個描述符就緒(一般是讀就緒或寫就緒),能夠通知程序進行相應的讀寫操作。這種機制的使用需要 select 、 poll 、 epoll 來配合。多個連接共用一個阻塞對象,應用程序只需要在一個阻塞對象上等待,無需阻塞等待所有連接。當某條連接有新的數(shù)據(jù)可以處理時,操作系統(tǒng)通知應用程序,線程從阻塞狀態(tài)返回,開始進行業(yè)務處理

Redis 服務采用 Reactor 的方式來實現(xiàn)文件事件處理器(每一個網(wǎng)絡連接其實都對應一個文件描述符) 

Redis基于Reactor模式開發(fā)了網(wǎng)絡事件處理器,這個處理器被稱為文件事件處理器。它的組成結構為4部分:多個套接字、IO多路復用程序、文件事件分派器、事件處理器。因為文件事件分派器隊列的消費是單線程的,所以Redis才叫單線程模型。

IO多路復用的具體實現(xiàn)select、poll、epoll

select

select 其實就是把NIO中用戶態(tài)要遍歷的fd數(shù)組(我們的每一個socket鏈接,安裝進ArrayList里面的那個)拷貝到了內(nèi)核態(tài),讓內(nèi)核態(tài)來遍歷,因為用戶態(tài)判斷socket是否有數(shù)據(jù)還是要調(diào)用內(nèi)核態(tài)的,所有拷貝到內(nèi)核態(tài)后,這樣遍歷判斷的時候就不用一直用戶態(tài)和內(nèi)核態(tài)頻繁切換了。select方式,既做到了一個線程處理多個客戶端連接(文件描述符),又減少了系統(tǒng)調(diào)用的開銷(多個文件描述符只有一次 select 的系統(tǒng)調(diào)用 + N次就緒狀態(tài)的文件描述符的 read 系統(tǒng)調(diào)用。

select函數(shù)的執(zhí)行流程:

1、select是一個阻塞函數(shù),當沒有數(shù)據(jù)時,會一直阻塞在select那一行。

2、當有數(shù)據(jù)時會將rset中對應的那一位置為1。

3、select函數(shù)返回,不再阻塞。

4、遍歷文件描述符數(shù)值,判斷那個fd被置位了。

5、讀取數(shù)據(jù),然后處理。

優(yōu)點:

select系統(tǒng)調(diào)用后,返回了一個置位后的&rset,這樣用戶態(tài)只需進行很簡單的二進制比較,就能很快知道哪些socket需要read數(shù)據(jù),有效提高了效率。

缺點:

1、bitmap最大1024位,一個進程最多只能處理1024個客戶端。

2、&rset不可重用,每次socket有數(shù)據(jù)就相應的位會被置位。

3、文件描述符數(shù)組拷貝到了內(nèi)核態(tài)(只不過無系統(tǒng)調(diào)用切換上下文的開銷。(內(nèi)核層可優(yōu)化為異步事件通知)),仍然有開銷。select 調(diào)用需要傳入 fd 數(shù)組,需要拷貝一份到內(nèi)核,高并發(fā)場景下這樣的拷貝消耗的資源是驚人的。(可優(yōu)化為不復制)

4、select并沒有通知用戶態(tài)哪一個socket有數(shù)據(jù),仍然需要O(n)的遍歷。select 僅僅返回可讀文件描述符的個數(shù),具體哪個可讀還是要用戶自己遍歷。(可優(yōu)化為只返回給用戶就緒的文件描述符,無需用戶做無效的遍歷)。

poll

poll的執(zhí)行流程:

1、將五個fd從用戶態(tài)拷貝到內(nèi)核態(tài)。

2、poll為阻塞方法,執(zhí)行poll方法,如果有數(shù)據(jù)會將fd對應的revents置為POLLIN。

3、poll方法返回。

4、循環(huán)遍歷,查找哪個fd被置位為POLLIN了。

5、將revents重置為0便于復用。

6、對置位的fd進行讀取和處理。

優(yōu)點:

1、poll使用pollfd數(shù)組來代替select中的bitmap,數(shù)組沒有1024的限制,可以一次管理更多的client。它和 select 的主要區(qū)別就是,去掉了 select 只能監(jiān)聽 1024 個文件描述符的限制。

2、當pollfds數(shù)組中有事件發(fā)生,相應的revents置位為1,遍歷的時候又置位回零,實現(xiàn)了pollfd數(shù)組的重用。

缺點:

poll 解決了select缺點中的前兩條,其本質(zhì)原理還是select的方法,還存在select中原來的問題。

1、pollfds數(shù)組拷貝到了內(nèi)核態(tài),仍然有開銷。

2、poll并沒有通知用戶態(tài)哪一個socket有數(shù)據(jù),仍然需要O(n)的遍歷。

epoll

epoll 是非阻賽的。

epoll的執(zhí)行流程:

1、當有數(shù)據(jù)的時候,會把相應的文件描述符“置位”,但是epool沒有revent標志位,所以并不是真正的置位。這時候會把有數(shù)據(jù)的文件描述符放到隊首。

2、epoll會返回有數(shù)據(jù)的文件描述符的個數(shù)。

3、根據(jù)返回的個數(shù) 讀取前N個文件描述符即可。

4、讀取、處理。

三步調(diào)用:

1、epoll_create:創(chuàng)建一個epoll句柄。

2、epoll_ctl:向內(nèi)核添加、修改或刪除要監(jiān)控的文件描述符。

3、epoll_wait:類似發(fā)起了select()調(diào)用。

總結

多路復用快的原因在于,操作系統(tǒng)提供了這樣的系統(tǒng)調(diào)用,使得原來的 while 循環(huán)里多次系統(tǒng)調(diào)用,變成了一次系統(tǒng)調(diào)用 + 內(nèi)核層遍歷這些文件描述符。

epoll是現(xiàn)在最先進的IO多路復用器,Redis、Nginx,linux中的Java NIO都使用的是epoll。這里“多路”指的是多個網(wǎng)絡連接,“復用”指的是復用同一個線程。

1、一個socket的生命周期中只有一次從用戶態(tài)拷貝到內(nèi)核態(tài)的過程,開銷小。

2、使用event事件通知機制,每次socket中有數(shù)據(jù)會主動通知內(nèi)核,并加入到就緒鏈表中,不需要遍歷所有的socket。

在多路復用IO模型中,會有一個內(nèi)核線程不斷地去輪詢多個 socket 的狀態(tài),只有當真正讀寫事件發(fā)送時,才真正調(diào)用實際的IO讀寫操作。因為在多路復用IO模型中,只需要使用一個線程就可以管理多個socket,系統(tǒng)不需要建立新的進程或者線程,也不必維護這些線程和進程,并且只有真正有讀寫事件進行時,才會使用IO資源,所以它大大減少來資源占用。

多路I/O復用模型是利用 select、poll、epoll 可以同時監(jiān)察多個流的 I/O 事件的能力,在空閑的時候,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態(tài)中喚醒,于是程序就會輪詢一遍所有的流(epoll 是只輪詢那些真正發(fā)出了事件的流),并且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。

 采用多路 I/O 復用技術可以讓單個線程高效的處理多個連接請求(盡量減少網(wǎng)絡 IO 的時間消耗),且 Redis 在內(nèi)存中操作數(shù)據(jù)的速度非??欤簿褪钦f內(nèi)存內(nèi)的操作不會成為影響Redis性能的瓶頸。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Redis 在真實世界的 5 個用法

    Redis 在真實世界的 5 個用法

    Redis是一個開源的使用ANSI C語言編寫、支持網(wǎng)絡、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API這篇文章主要介紹了Redis 在真實世界的 5 個用法,需要的朋友可以參考下
    2018-03-03
  • Redis模糊查詢的幾種實現(xiàn)方法

    Redis模糊查詢的幾種實現(xiàn)方法

    本文主要介紹了Redis模糊查詢的幾種實現(xiàn)方法,包括兩種方法KEYS , SCAN,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • redis中RedissonLock如何實現(xiàn)等待鎖的

    redis中RedissonLock如何實現(xiàn)等待鎖的

    本文主要介紹了redis中RedissonLock如何實現(xiàn)等待鎖的,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Redis配置文件最佳實踐

    Redis配置文件最佳實踐

    這篇文章主要介紹了Redis配置文件詳解,本文主要是根據(jù)Redis6.0.x版本的配置文件講解,其它版本的也可以當做一個參考,需要的朋友可以參考下
    2025-05-05
  • Redis搭建一主多從的實現(xiàn)步驟

    Redis搭建一主多從的實現(xiàn)步驟

    本文主要介紹了在Linux環(huán)境下配置Redis的一主兩從架構,包括創(chuàng)建配置文件,設置不同端口,啟動服務,以及通過inforeplication命令檢查復制狀態(tài),感興趣都可以了解一下
    2025-10-10
  • Redis?ziplist?壓縮列表的源碼解析

    Redis?ziplist?壓縮列表的源碼解析

    ziplist 是一個經(jīng)過特殊編碼的雙向鏈表,旨在提高內(nèi)存效率,它存儲字符串和整數(shù)值,其中整數(shù)被編碼為實際整數(shù)而不是一系列字符,這篇文章主要介紹了Redis?ziplist?壓縮列表的源碼解析,需要的朋友可以參考下
    2022-06-06
  • 使用Redis實現(xiàn)分布式鎖的代碼演示

    使用Redis實現(xiàn)分布式鎖的代碼演示

    edis作為一個高性能的內(nèi)存數(shù)據(jù)庫,提供了多種機制來實現(xiàn)分布式鎖,本文將詳細介紹如何使用Redis實現(xiàn)分布式鎖,感興趣的朋友一起看看吧
    2025-04-04
  • Redis RDB快照持久化及寫操作禁止問題排查與解決

    Redis RDB快照持久化及寫操作禁止問題排查與解決

    本文主要介紹了Redis RDB快照持久化及寫操作禁止問題排查與解決,由于?stop-writes-on-bgsave-error?選項處于啟用狀態(tài),所以寫操作被禁止,下面就來介紹一下,感興趣的可以了解一下
    2025-04-04
  • Redis定時任務原理的實現(xiàn)

    Redis定時任務原理的實現(xiàn)

    本文主要是基于?redis?6.2?源碼進行分析定時事件的數(shù)據(jù)結構和常見操作,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 談談Redis分布式鎖的正確實現(xiàn)方法

    談談Redis分布式鎖的正確實現(xiàn)方法

    這篇文章主要給大家介紹了關于Redis分布式鎖的正確實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-08-08

最新評論

刚察县| 利川市| 奉节县| 肇东市| 博罗县| 延安市| 宝山区| 永安市| 宜都市| 南召县| 上杭县| 博爱县| 大田县| 仪征市| 西丰县| 龙井市| 泰宁县| 凌海市| 乌恰县| 宜宾市| 开封市| 青冈县| 崇礼县| 西充县| 邵武市| 河曲县| 泽库县| 茂名市| 西丰县| 富民县| 汤原县| 靖边县| 普安县| 泗洪县| 锦屏县| 调兵山市| 澜沧| 恩施市| 达尔| 乳山市| 屏东市|