黑马程序员技术交流社区
标题: 【上海校区】Python高级网络编程系列之第2篇 [打印本页]
作者: fangtaoa 时间: 2018-10-16 17:07
标题: 【上海校区】Python高级网络编程系列之第2篇
在上一篇中,我们深入探讨了TCP/IP协议的11种状态,理解这些状态对我们编写服务器的时候有很大的帮助,但一般写服务器都是使用C/Java语言,因为这些语言对高并发的支持特别好。我们写的这些简单的服务器主要是为了深入学习TCP/IP协议、IO操作以及Python中协程的原理。在上一篇中也提到非阻塞这个概念,在这一篇中,我们继续深入探讨IO模型,因为理解IO操作对我们深入学习异步编程有很大帮助。所以在这一节中我们主要是从Linux内核态和用户态的层面来考虑IO操作时会发生什么样的事情,Linux内核会做什么。
一、常见5种IO模型
1.阻塞IO模型
阻塞IO模型图如下:
说明:
(1).当上层应用程序调用recv系统调用时,进程会从用户态切换到内核态;如果此时对方没有发送数据来(内核缓冲区没有数据),那么应用程序将会被阻塞(默认行为,被Linux内核阻塞)。
(2).当对方把数据发送过来了之后,Linux内核会自动把数据copy到用户空间的缓冲区中,然后进程恢复执行,执行下一步操作!
2.非阻塞IO模型
非阻塞IO模型图如下:
说明:
(1). 进程中需要将套接字设置为非阻塞模式;
(2). 进程会一直调用recv()函数去接收数据,如果缓冲区中没有数据,那么进程也不会被阻塞,只是recv()会返回一个错误码(EWOULDBLOCK)
(3). 进程会不断轮询有没有数据到来。这样会造成进程忙等待。大量消耗CPU资源。因此很少使用,一般和select或epoll机制一起使用。
3.IO复用模型
IO复用模型图如下:
说明:
(1). 进程使用select机制(该机制由Linux内核支持,避免了进程忙等待),目的是去轮询文件描述符的状态变化;
(2). 当select管理的文件描述符没有变化时,进程也会被阻塞;但是使用select可以管理多个文件描述符,效率就提高了。这就不像非阻塞模型中,去轮询recv()。
(3). select可以看成一个管家,使用select来管理多个IO。
一旦检测到一个或多个IO有我们感兴趣的事件发生时,select函数将返回,返回值是检测到的事件个数。
(4). select函数可以设置超时时间, 这样可以避免进程处于干等待状态,长期僵死
(5). 和非阻塞IO模型相比,select IO复用模型相当于提前阻塞了。当有数据来到时,可以直接调用recv()来获取数据。
4.信号驱动IO
信号驱动IO模型图如下:
说明:
(1). 在上层应用程序中会建立SIGIO信号的处理程序。当缓冲区有数据来到时,内核会发送数据到上层应用程序。
(2). 当上层应用程序收到信号后,调用recv()函数,因为缓冲区有数据,recv()函数一般不会被阻塞。
(3). 这种模型用的比较少,属于典型的"拉模型",即,上层应用程序需要调用recv()函数把数据拉进来。
5.异步IO模型
异步IO模型图如下:
说明:
(1). 上层应用程序调用aio_read函数,同时会提交一个应用层的缓冲区给内核写入数据;调用完毕后,应用程序不会被阻塞,可以继续执行其他任务。
(2). 当数据过来时,Linux内核主动把数据从内核空间copy到用户空间,然后再给应用程序发送一个信号,告诉进程数据已经复制过去了,你赶紧处理数据吧。
(3). 这是一个"推模式",效率非常之高,应用程序有异步处理的能力(在Linux内核的辅助下,进程在处理其他任务的同时,也可以进行IO通讯)。与信号驱动IO模型相比,应用程序不需要调用recv()来接收数据!
(4). 异步IO是什么?
应用程序在处理其他事情的同时,还可以接收数据。
小结:通过对比五种IO模型,我们可以很明显发现他们的区别以及效率,一般在开发中IO复用模型和异步IO模型是最常用的模型!
五种模型的对比图:
作者: 不二晨 时间: 2018-10-18 16:14
奈斯
作者: 魔都黑马少年梦 时间: 2018-11-1 16:23
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |