非阻塞 IO
  当我们调用套接字的读写方法,默认它们是阻塞的,比如 read 方法要传递进去一个参数n,表示读取这么多字节后再返回,如果没有读够线程就会卡在那里,直到新的数据到来或者连接关闭了,read 方法才可以返回,线程才能继续处理。而 write 方法一般来说不会阻塞,除非内核为套接字分配的写缓冲区已经满了,write 方法就会阻塞,直到缓存区中有空闲空间挪出来了。
  非阻塞 IO 在套接字对象上提供了一个选项 Non_Blocking,当这个选项打开时,读写方法不会阻塞,而是能读多少读多少,能写多少写多少。能读多少取决于内核为套接字分配的
读缓冲区内部的数据字节数,能写多少取决于内核为套接字分配的写缓冲区的空闲空间字节数。读方法和写方法都会通过返回值来告知程序实际读写了多少字节。有了非阻塞 IO 意味着线程在读写 IO 时可以不必再阻塞了,读写可以瞬间完成然后线程可以继续干别的事了。
事件轮询 (多路复用)
  非阻塞 IO 有个问题,那就是线程要读数据,结果读了一部分就返回了,线程如何知道何时才应该继续读。也就是当数据到来时,线程如何得到通知。写也是一样,如果缓冲区满了,写不完,剩下的数据何时才应该继续写,线程也应该得到通知。

  事件轮询 API 就是用来解决这个问题的,最简单的事件轮询 API 是 select 函数,它是操作系统提供给用户程序的 API。输入是读写描述符列表 read_fds & write_fds,输出是与之对应的可读可写事件。同时还提供了一个 timeout 参数,如果没有任何事件到来,那么就最多等待 timeout 时间,线程处于阻塞状态。一旦期间有任何事件到来,就可以立即返回。时间过了之后还是没有任何事件到来,也会立即返回。拿到事件后,线程就可以继续挨个处理相应的事件。处理完了继续过来轮询。于是线程就进入了一个死循环,我们把这个死循环称为事件循环,一个循环为一个周期。
  每个客户端套接字 socket 都有对应的读写文件描述符。
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 系统调用同时处理多个通道描述符的读写事件,因此我们将这类系统调用称为多路复用 API。现代操作系统的多路复用 API 已经不再使用 select 系统调用,而改用 epoll(linux)和 kqueue(freebsd & macosx),因为 select 系统调用的性能在描述符特别多时性能会非常差。它们使用起来可能在形式上略有差异,但是本质上都是差不多的,都可以使用上面的伪代码逻辑进行理解。
服务器套接字 serversocket 对象的读操作是指调用 accept 接受客户端新连接。何时有新连
  接到来,也是通过 select 系统调用的读事件来得到通知的。事件轮询 API 就是 Java 语言里面的 NIO 技术Java 的 NIO 并不是 Java 特有的技术,其它计算机语言都有这个技术,只不过换了一个词汇,不叫 NIO 而已。
指令队列
  Redis 会将每个客户端套接字都关联一个指令队列。客户端的指令通过队列来排队进行顺序处理,先到先服务。
响应队列
  Redis 同样也会为每个客户端套接字关联一个响应队列。Redis 服务器通过响应队列来将指令的返回结果回复给客户端。 如果队列为空,那么意味着连接暂时处于空闲状态,不需要去获取写事件,也就是可以将当前的客户端描述符从 write_fds 里面移出来。等到队列有数据了,再将描述符放进去。避免 select 系统调用立即返回写事件,结果发现没什么数据可以写。出这种情况的线程会飙高 CPU。
定时任务
  服务器处理要响应 IO 事件外,还要处理其它事情。比如定时任务就是非常重要的一件事。如果线程阻塞在 select 系统调用上,定时任务将无法得到准时调度。那 Redis 是如何解决这个问题的呢?
  Redis 的定时任务会记录在一个称为最小堆的数据结构中。这个堆中,最快要执行的任务排在堆的最上方。在每个循环周期,Redis 都会将最小堆里面已经到点的任务立即进行处理。处理完毕后,将最快要执行的任务还需要的时间记录下来,这个时间就是 select 系统调用的 timeout 参数。因为 Redis 知道未来 timeout 时间内,没有其它定时任务需要处理,所以可以安心睡眠 timeout 的时间。Nginx 和 Node 的事件处理原理和 Redis 也是类似的
 
 
 

redis之线程IO模型的更多相关文章

  1. 通过实例理解Java网络IO模型

    网络IO模型及分类 网络IO模型是一个经常被提到的问题,不同的书或者博客说法可能都不一样,所以没必要死抠字眼,关键在于理解. Socket连接 不管是什么模型,所使用的socket连接都是一样的. 以 ...

  2. Reids原理之IO模型

    众所周知Redis是单进程单线程的应用,在如今多核横行的时代,我们不免有疑问,单线程的redis怎么就成了高性能的代表 当有多个线程同时调用redis的时候,那么单线程的redis是怎么处理的呢,这里 ...

  3. redis的线程模型是什么?

    1.面试题 redis和memcached有什么区别? redis的线程模型是什么? 为什么单线程的redis比多线程的memcached效率要高得多(为什么redis是单线程的但是还可以支撑高并发) ...

  4. python(40)- 进程、线程、协程及IO模型

    一.操作系统概念 操作系统位于底层硬件与应用软件之间的一层.工作方式:向下管理硬件,向上提供接口. 操作系统进行进程切换:1.出现IO操作:2.固定时间. 固定时间很短,人感受不到.每一个应用层运行起 ...

  5. 2.redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?

    作者:中华石杉 面试题 redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 面试官心理分析 这个是问 redis 的时候,最基本的 ...

  6. redis和memcached有什么区别?redis的线程模型是什么?为什么单线程的redis比多线程的memcached效率要高得多(为什么redis是单线程的但是还可以支撑高并发)?

    1.redis和memcached有什么区别? 这个事儿吧,你可以比较出N多个区别来,但是我还是采取redis作者给出的几个比较吧 1)Redis支持服务器端的数据操作:Redis相比Memcache ...

  7. redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?

    redis 和 memcached 有啥区别? redis 支持复杂的数据结构 redis 相比 memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作.如果需要缓存能够支持更复杂的结构 ...

  8. 《【面试突击】— Redis篇》-- Redis的线程模型了解吗?为啥单线程效率还这么高?

    能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis的线程模型了解吗?为啥单线程效率还这 ...

  9. 深入学习redis 的线程模型

    一.redis 的线程模型 redis 内部使用文件事件处理器 file event handler,它是单线程的,所以redis才叫做单线程模型.它采用IO多路复用机制同时监听多个 socket,将 ...

随机推荐

  1. Java正则表达式验证IP,邮箱,电话

     引言     java中我们会常用一些判断如IP.电子邮箱.电话号码的是不是合法,那么我们怎么来判断呢,答案就是利用正则表达式来判断了,废话不多说,下面就是上代码. 1:判断是否是正确的IP  1 ...

  2. Razor_02 第一个应用程序+Model+EF 添加

    第一个应用程序+Model+EF 添加 小试牛刀 今天 也试了试 边说边写,但是 有时候 编辑器不给力,或者网路不给力,倒是浪费大家时间,所以今天录制完了就裁切了 部分视频,如果有不清楚的地方,可以留 ...

  3. 使用Node.js简单创建一个服务器

    首先,我们要了解Node.js不是一种语言,它只是一个除了浏览器之外的,可以运行js的环境. 其次,Node能做些什么 ? web服务器.  命令行工具.   网络爬虫. 桌面应用程序开发等 3.接下 ...

  4. JS基础语法---分支语句之:switch-case语句---3个练习

    switch-case语句---分支语句---多分支语句 语法: switch(表达式){ case 值1:代码1;break; case 值2:代码2;break; case 值3:代码3;brea ...

  5. 版本管理·玩转git(日志查看与版本切换)

    如果你想更清晰地学习git,你必须要了解3个重要区域. 工作区:即开发者的工作目录 暂存区:修改已被记录,但尚未录入版本库的区域 版本库:存储变化日志及版本信息 当你在工作区进行开发工作时,git会记 ...

  6. Android Studio compile error ---- enum constant INSTANT_RUN_REPLACEMENT does not

    原文:http://stackoverflow.com/questions/34868876/android-studio-compile-error-enum-constant-instant-ru ...

  7. Python用openpyxl读写Excel

    openpyxl是一个用于读写Excel 2010 xlsx文件的python库.openpyxl官方文档:https://openpyxl.readthedocs.io/en/stable/ 一.安 ...

  8. Python中线程的使用

    并发:多个任务同一时间段进行 并行:多个任务同一时刻进行 线程的实现 线程模块 Python通过两个标准库_thread 和threading,提供对线程的支持 , threading对_thread ...

  9. 05webpack-webpack-dev-server时时跟新-第2种方式

    <!--14 第一种方式 自动打开浏览器 端口号 指定托管的跟目录 启动热刷新 这种是在webpack.json中去配置的 直接在package中 写 将“script”:{ "dev ...

  10. 使用响应的json数据判断订单查询是否成功;

    #查询中通快递import requestsrr=requests.session()headers={"User-Agent": "Mozilla/5.0 (Windo ...