0

0

一文带你快速了解Redis中的线程IO模型

青灯夜游

青灯夜游

发布时间:2021-12-21 10:19:32

|

2581人浏览过

|

来源于掘金社区

转载

redis是单线程的,但为什么那么快尼?原因之一就是redis使用非阻塞io与多路复用处理大量的客户端连接。下面本篇文章就来带大家了解一下redis中的线程io模型,希望对大家有所帮助!

一文带你快速了解Redis中的线程IO模型

Redis是一个单线程的应用程序,NodeJs、Nginx都是单线程,它们都属于服务器高性能的典范。【相关推荐:Redis视频教程

Redis之所以是单线程还能这么快的原因:

其一是因为它所有的数据都在内存当中,所有的运算都是内存级别的运算,所以使用redis时,要注意时间复杂度为O(n)的指令,因为是单线程的,如果数据量太大,会让其他指令被阻塞等待;

其二是因为redis使用非阻塞IO与多路复用处理大量的客户端连接。

非阻塞IO

当我们使用套接字的读写方法时,默认是阻塞的,

即调用read方法传递一个参数n,表示最多读取n个字节后返回,如果一个字节都没有,线程就会在read方法这里持续等待,直到有数据过来或者连接被关闭,read方法此时返回,线程才能执行下面的逻辑,

write方法一般不会阻塞,除非内核为套接字分配的写缓冲区满了,write方法才会阻塞,一直到缓存区中有空间闲出来。

下图是套接字读写的细节流程。

1.png

非阻塞IO在使用套接字时提供了一个选项Non_Blocking,当这个选项打开时,读写方法不会阻塞,而是能读多少读多少,能写多少写多少,

能读多少取决与内核为套接字分配的读缓冲区的数据字节数,能写多少取决于内核为套接字写缓冲区分配的数据字节数,

读写方法都会通过返回值告诉程序读写了多少字节数。

非阻塞IO意味着读写时,线程不必再被阻塞着,读写可以瞬间完成,线程可以继续往下做别的事情。

多路复用(事件轮询)

非阻塞IO虽然很快,但是也带来一个问题,线程读数据,读了一部分就返回了,没有读完,剩下的数据何时继续读?,写数据,缓冲区满了,没有写完,剩下的数据何时继续写?

当可以继续读或者可以继续写时,应该给应用程序一个通知,告诉应用程序可以继续读或者继续写,事件轮询API就是用来处理这个问题的。

select

操作系统提供了一个select函数给用户程序,输入是读写描述符列表 read_fds & write_fds,输出是与之对应的可读可写事件,

同时还提供了timeout参数,线程最多等待timeout的时间,在这期间有事件过来,方法立刻返回,线程往下处理,如果超过timeout时间,方法也会返回,

如果拿到事件了,线程即可挨个处理相应的事件,处理完了以后继续调用 select api 轮询,所以该线程其实是一个死循环,不停的 select,不停的处理,来回这样,这个死循环被称之为事件循环,一个循环即一个周期。

2.png

事件循环伪代码:

while True
    read_events, write_events = select(read_fds, write_fds, timeout)
    for event in read_events:
        handle_read(event.fd)
    for event in write_events:
        handle_write(event.fd)
    handle_others() # 做其他的逻辑处理,处理定时任务等等

通过select函数我们可以处理多个通道描述符的读写事件,所以将select这类的系统函数调用称之为多路复用API,

现代操作系统的多路复用API已经不使用select系统调用,改用epoll(linux)和kqueue(FreeBSD、macosx),

select的性能在描述符变多时会变得很差,epoll与select使用起来略有差异,不过都可以用上面的伪代码理解,都是当描述符发生事件时,循环对描述符的事件做出处理,

serversocket对象的读操作是指调用accept接受客户端新连接,何时有连接来临,也是通过select调用的读事件通知的。

Java中的NIO技术就是事件轮询,其他语言也有这个技术。

指令队列

Redis为每一个客户端套接字关联一个指令队列,客户端发来的指令通过队列进行先进先出的顺序处理。

响应队列

同样Redis返回的结果也通过为每个客户端关联的一个队列返回,如果队列为空,则暂时不需要去获取写事件,

此时会将该客户端描述符从write_fds里移除,等队列有数据的时候,再将描述符放进去,这样可以避免select系统调用返回写事件时,发现没数据可写,造成空轮询、无用轮询,对机器CPU的消耗。

定时任务

服务器不单要响应IO事件,有些其他的事情也需要处理,例如应用程序自身的定时任务,如果线程阻塞在select调用上,等待select的返回,这会造成有些定时任务到期了,却没有执行,

Redis的定时任务记录在一个称为 最小堆 的数据结构中,这个堆中,最快要执行的任务排在最上方,每个循环周期里,redis会对堆中已经到时间点的任务进行处理,

处理完毕后,将堆中即将要执行的任务还需要的时间记录下来,再次调用select时,这个时间就是timeout的值,在这期间内不会有其他任务需要执行了,redis可以放心的最多阻塞这么久,然后到时间后进行相应的处理。

NodeJs和Nginx的事件处理原理和Redis也是类似的形式。

更多编程相关知识,请访问:编程视频!!

相关专题

更多
Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

37

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

37

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

16

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

交互式图表和动态图表教程汇总
交互式图表和动态图表教程汇总

本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

45

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

9

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 6.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号