核心代码,注释必读
// download:3w 52xueit com
vue 2.x 响应式
Object.defineProperty
爱学it学无止境
以对所有类型的文件执行I/O操作
要实现通用I/O,就必须保证每一文件系统和设备驱动程序都实现了相同的I/O系统调用
传统阻塞式I/O
大部分程序使用的I/O模型都是单个进程每次只在一个文件描述符上执行I/O操作,每次I/O系统调用都会阻塞,直到完成数据传输
磁盘文件是个特例:内核采用缓冲区cache来加速磁盘I/O请求,因而一旦情感求的数据传输到内核的缓冲区cache,对磁盘的write()操作将立即返回。因而不用等到数据实际写入磁盘后才会返回(除非在打开文件时指定了O_SYNC标志)。
与之对应的是,read()调用将数据从内核缓冲区cache移动到用户的缓冲区,如果请求的数据不在内核缓冲区cache,那么内核就会让进程休眠,同时执行对磁盘的读写操作
非阻塞I/O
在打开文件时,指定O_NONBLOCK标志
若open()调用未能立即打开文件,则返回错误,而不是陷入阻塞。(有一种情况属于例外,调用open()操作FIFO可能会陷入阻塞)
调用open()成功后,后续的I/O操作也是非阻塞的。若I/O系统调用未能立即完成,则可能只会传输部分数据或系统调用失败,并返回EAGAIN 或EWOULDBLOCK错误
管道、FIFO、套接字、设备都支持非阻塞模式。因为无法通过open()来获取管道和套接字的文件描述符,所以要启用非阻塞标识,就必须使用fcntl()的F_SETFL命令
fcntl():针对一打开的文件,获取或修改其访问模式和状态标识(这些值是通过open()调用的flag参数设置的)
fcntl()的F_SETFL命令:修改打开文件的某些状态标识。允许更改的标识有O_APPEND, O_NONBLOCK, O_NOATIME, O_ASYNC和O_DIRECT
使用fcntl()修改文件的状态标识,适用于如下场景
文件不是由调用程序打开的,所以程序也无法使用open()调用来控制文件的状态标识
文件描述符的获取是通过open()之外的系统调用,比如pipe(), socket()等
为了修改文件的状态标识,可以使用fcntl()的F_GETFL命令来获取当前标志的副本,然后修改需要变更的比特位,最后再次调用fcntl()的F_SETFL命令来更新此状态标志
int flags;
flags = fcntl(fd, F_GETFL);
if(flags==-1)
erExit("fcntl");
flags |= O_APPEND;
if(fcntl(fd, F_SETFL, flags)==-1)
errExit("fcntl");
非阻塞式I/O+多进程(多线程)
以非阻塞的方式检查文件描述符上是否可以进行I/O操作
同时检查多个文件描述符,看他们中的一个是否可以执行I/O操作
非阻塞式I/O可以让我们周期性的检查(“轮询”)某个文件描述符上是否可以执行I/O操作。例如,我们让一个输入文件描述符成为非阻塞式的,然后周期性的执行非阻塞的读操作。
如果我们需要同时检查多个文件描述符,那么就需要将他们都设为非阻塞的,然后依次对它们轮询。(浪费CPU)
如果不希望进程在堆文件描述符执行I/O操作时被阻塞,我们可以创建一个新的进程来执行I/O,此时父进程就可以去处理其他任务,而子进程将阻塞直到I/O操作完成。这种方案开销昂贵且复杂
使用多线程,占用较少的资源。但线程之间仍然需要通信,以告知其他线程有关I/O操作的状态,这使变成变得复杂
可选的备选方案:
IO多路复用允许进程同时检查多个文件描述符以找出它们中的任何一个是否可以执行IO操作,selct()和poll()
信号驱动IO是指当地有输入或数据可以写到指定的文件描述符上时,内核向请求数据的进程发送一个信号。进程可以处理其他任务,当IO操作可执行时通过接收信号来获得通知
epoll API是linux专有的特性,允许进程同时检查多个文件描述符,看其中任意一个是否能执行IO操作。当同时检查大量文件描述符时,epoll能提供更好的性能
以上都是实现同一个目标的技术----同时检查多个文件描述符,看他们是否准备好了执行IO操作
这些技术都不会执行实际的IO操作。他们只是告诉我们某个文件描述符已经处于就绪状态了,这时需要调用其他的系统调用来完成实际的IO操作
领取专属 10元无门槛券
私享最新 技术干货