缓冲与非缓冲I/O、直接与非直接I/O、阻塞与非阻塞I/O、同步与异步I/O

文件读写方式的各种差异,导致I/O的分类多种多样。最常见的有缓冲与非缓冲I/O、直接与非直接I/O、阻塞与非阻塞I/O、同步与异步I/O。

根据是否利用标准库缓存,可以把文件I/O分为缓冲I/O与非缓冲I/O。

  • 缓冲I/O,是指利用标准库缓存来加速文件的访问,而标准库内部再通过系统调度访问文件。

  • 非缓冲I/O,是指直接通过系统调用来访问文件,不再经过标准库缓存。

 这里所说的“缓冲”,是指标准库内部实现的缓存。比方说,你可能见到过,很多程序遇到换行时才真正输出,而换行前的内容,其实就是被标准库暂时缓存了起来。

根据是否利用操作系统的页缓存,可以把文件I/O分为直接I/O与非直接I/O。

  • 直接I/O,是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件。

  • 非直接I/O正好相反,文件读写时,先要经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘。

想要实现直接I/O,需要你在系统调用中,指定 O_DIRECT 标志。如果没有设置过,默认的是非直接I/O。

不过要注意,直接I/O、非直接I/O,本质上还是和文件系统交互。如果是在数据库等场景中,你还会看到,跳过文件系统读写磁盘的情况,也就是我们通常所说的裸I/O。

根据应用程序是否阻塞自身运行,可以把文件I/O分为阻塞I/O和非阻塞I/O:

扫描二维码关注公众号,回复: 12774293 查看本文章
  • 所谓阻塞I/O,是指应用程序执行I/O操作后,如果没有获得响应,就会阻塞当前线程,自然就不能执行其他任务。

  • 所谓非阻塞I/O,是指应用程序执行I/O操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果。

比方说,访问管道或者网络套接字时,设置 O_NONBLOCK 标志,就表示用非阻塞方式访问;而如果不做任何设置,默认的就是阻塞访问。

根据是否等待响应结果,可以把文件I/O分为同步和异步I/O:

  • 所谓同步I/O,是指应用程序执行I/O操作后,要一直等到整个I/O完成后,才能获得I/O响应(需要主动读写数据,如read、write等操作)。

  • 所谓异步I/O,是指应用程序执行I/O操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O完成后,响应会用事件通知的方式,告诉应用程序(操作系统来完成数据的读写)。

举个例子,在操作文件时,如果你设置了 O_SYNC 或者 O_DSYNC 标志,就代表同步I/O。如果设置了O_DSYNC,就要等文件数据写入磁盘后,才能返回;而O_SYNC,则是在O_DSYNC基础上,要求文件元数据也要写入磁盘后,才能返回。

再比如,在访问管道或者网络套接字时,设置了O_ASYNC选项后,相应的I/O就是异步I/O。这样,内核会再通过SIGIO或者SIGPOLL,来通知进程文件是否可读写。

我们可能会问 阻塞、非阻塞 I/O 与同步、异步 I/O 的区别和联系

通过定义可以看出阻塞/非阻塞和同步/异步,其实就是两个不同角度的 I/O 划分方式。它们描述的对象也不同,阻塞/非阻塞针对的是 I/O 调用者(即应用程序),而同步/异步针对的是 I/O 执行者(即系统)。

知乎上大神陈硕老师的回答:

在处理 IO 的时候,阻塞和非阻塞都是同步 IO(我们使用的select/poll/epoll /read/write等函数都是同步IO)。只有使用了特殊的 API 才是异步 IO。

猜你喜欢

转载自blog.csdn.net/u014608280/article/details/105492199
今日推荐