深入Redis(十)線程IO模型
阿新 • • 發佈:2018-08-20
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模型