1. 程式人生 > >深入Redis(十)線程IO模型

深入Redis(十)線程IO模型

input 異步 nec red data call {} 時間輪 必須

線程IO模型

首先必須記住的是,Redis是個單線程程序。

為什麽單線程還這麽快?

Redis所有數據都在內存裏,所有運算都是內存級別的運算,所以速度比在硬盤內操作更快。但是也正是由於是單線程,所以要小心使用那些時間復雜度O(n)的指令。

單線程如何處理那麽多的並發客戶端連接?

多路復用。

非阻塞IO

socket方法的讀寫默認都是阻塞的,在python中可以通過socket.socket().setblocking(False)來設置非阻塞IO。

時間輪詢(多路復用)

非阻塞IO有個問題就是,線程讀寫數據可能只做了一部分就返回了,什麽時候繼續讀數據,什麽時候繼續寫數據,應該有個方法來通知它們。

時間輪詢API就是來解決這個問題的,早期的select,後來的poll,現在的epoll和kqueque。

#基於select
import socket
import select
import queue


server = socket.socket()
server.bind((‘localhost‘, 8000))
server.listen()
server.setblocking(0)

msg = {}

inputs = [server]
outputs = []

while True:
    readable, writeable, exceptional = select.select(inputs, outputs, inputs)
    
    for r in readable:
        if r is server:
            conn, addr = r.accept()
            conn.setblocking(0)
            inputs.append(conn)
            msg[conn] = queue.Queue()
        else:
            try:
                data = r.recv(1024)
                msg[r].put(data)
                outputs.append(r)
            except ConnectionResetError:
                inputs.remove(r)
                continue

    for w in writeable:
        data = msg[w].get()
        w.send(data)
        outputs.remove(w)

    for e in exceptional:
        if e in outputs:
            outputs.remove(e)
        inputs.remove(e)
        del msg[e]
# 自動匹配版select,在linux中自動使用epoll,在windows中只能select,在bsd或mac中自動kqueue
import socket
import selectors


server = socket.socket()
server.bind((‘localhost‘, 8000))
server.listen()
server.setblocking(0)


sel = selectors.DefaultSlector()


def accept(server, mask):
    conn, addr = server.accept()
    conn.setblocking(0)
    sel.register(conn, mask, read)


def read(conn, mask):
    data = conn.recv(1024)
    if data:
        conn.send(data)
    else:
        sel.unregister(conn)
        conn.close()


sel.register(server, selectors.EVENT_READ, accept)


while True:
    events = sel.select()
    for key, mask in events:
        callback = key.data
        obj = key.fileobj
        callback(obj, mask)

不過這些都不用我們去實現,Redis內部已經替我們實現了這種輪詢機制,只要記住多路復用是非阻塞IO,並不是異步操作。

深入Redis(十)線程IO模型