深入Redis(十)线程IO模型

线程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,并不是异步操作。

猜你喜欢

转载自www.cnblogs.com/ikct2017/p/9503422.html