前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高级IO之非阻塞IO和阻塞IO

高级IO之非阻塞IO和阻塞IO

作者头像
Linux兵工厂
发布2024-02-27 17:28:29
2770
发布2024-02-27 17:28:29
举报
文章被收录于专栏:Linux兵工厂

unsetunset非阻塞I/Ounsetunset

非阻塞 I/O(Input/Output)是一种在进行文件和套接字操作时不阻塞进程的机制。在 Linux 中,非阻塞 I/O 可以通过设置文件描述符(File Descriptor)为非阻塞模式来实现。

文件描述符的非阻塞设置

  1. 使用 fcntl 函数:
代码语言:javascript
复制
#include <fcntl.h>

int flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);

上述代码将文件描述符 fd 设置为非阻塞模式。

  1. 使用 ioctl 函数:
代码语言:javascript
复制
#include <sys/ioctl.h>

ioctl(fd, FIONBIO, &arg);  // 其中 arg 为 0 表示阻塞,为 1 表示非阻塞

这将 fd 设置为非阻塞(arg 为 1)或阻塞(arg 为 0)。

非阻塞 I/O 操作

  1. 非阻塞读取:
代码语言:javascript
复制
ssize_t n = read(fd, buf, sizeof(buf));
if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
    // 没有数据可读,可以稍后再试或进行其他操作
} else {
    // 读取成功,处理数据
}
  1. 非阻塞写入:
代码语言:javascript
复制
ssize_t n = write(fd, buf, sizeof(buf));
if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
    // 写入缓冲区已满,可以稍后再试或进行其他操作
} else {
    // 写入成功,继续写入或进行其他操作
}

selectpoll 函数

  1. 使用 select 函数:
代码语言:javascript
复制
#include <sys/select.h>

fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);

struct timeval timeout;
timeout.tv_sec = 5;  // 设置超时时间为 5 秒
timeout.tv_usec = 0;

int ready = select(fd + 1, &read_fds, NULL, NULL, &timeout);
if (ready == -1) {
    // 处理错误
} else if (ready == 0) {
    // 超时,没有数据可读
} else {
    // 文件描述符 `fd` 上有数据可读
}
  1. 使用 poll 函数:
代码语言:javascript
复制
#include <poll.h>

struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;

int ready = poll(fds, 1, 5000);  // 设置超时时间为 5000 毫秒
if (ready == -1) {
    // 处理错误
} else if (ready == 0) {
    // 超时,没有数据可读
} else {
    // 文件描述符 `fd` 上有数据可读
}

这些函数和方法允许在进行 I/O 操作时检查文件描述符的状态,从而避免阻塞。非阻塞 I/O 对于需要实时响应的应用程序非常有用,例如网络通信、事件驱动的系统等。

非阻塞I/O的优缺点

非阻塞 I/O(Non-blocking I/O)是一种在进行文件和套接字操作时,应用程序可以在操作未完成的情况下继续执行其他任务的机制。以下是非阻塞 I/O 的优点和缺点:

优点

  1. 高并发性:
    • 非阻塞 I/O 允许应用程序同时处理多个连接或文件,提高了系统的并发性。
  2. 实时响应:
    • 由于应用程序可以在 I/O 操作进行的同时执行其他任务,非阻塞 I/O 有助于提高系统的实时响应性。
  3. 资源利用率高:
    • 在等待 I/O 操作完成时,应用程序不会被阻塞,系统可以调度其他任务,提高了系统资源的利用率。
  4. 避免死锁:
    • 非阻塞 I/O 操作减少了在多线程或多进程环境中发生死锁的风险,因为应用程序可以处理未完成的操作而不是等待。
  5. 适用于事件驱动模型:
    • 非阻塞 I/O 适用于事件驱动的应用程序,允许程序在事件发生时及时响应,而不必等待 I/O 操作完成。

缺点

  1. 复杂性增加:
    • 非阻塞 I/O 模型相对于阻塞 I/O 更为复杂,因为应用程序需要管理和处理未完成的 I/O 操作。
  2. 编程难度提高:
    • 编写使用非阻塞 I/O 的程序可能会更加复杂,需要考虑状态管理、错误处理等方面的问题。
  3. 部分系统不支持:
    • 有些系统对非阻塞 I/O 的支持不完整,可能需要特殊的操作系统或硬件支持。
  4. 可能增加系统负担:
    • 在某些情况下,频繁地进行非阻塞轮询可能会增加系统的负担,因为需要不断地检查 I/O 操作的状态。
  5. 可能导致忙等待:
    • 如果不使用适当的等待机制,非阻塞 I/O 可能导致忙等待,消耗系统资源。

unsetunset非阻塞I/O并发读取unsetunset

非阻塞 I/O 可以通过设置文件描述符为非阻塞模式,以及使用适当的系统调用来实现并发读取。下面是一个简单的示例,演示如何使用非阻塞 I/O 实现并发读取:

代码语言:javascript
复制
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

int set_nonblocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1) {
        perror("fcntl");
        return -1;
    }

    flags |= O_NONBLOCK;

    if (fcntl(fd, F_SETFL, flags) == -1) {
        perror("fcntl");
        return -1;
    }

    return 0;
}

int main() {
    int fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 设置文件描述符为非阻塞模式
    if (set_nonblocking(fd) == -1) {
        return 1;
    }

    char buffer[1024];
    ssize_t n;

    // 进行并发读取
    while (1) {
        n = read(fd, buffer, sizeof(buffer));

        if (n == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 没有数据可读,可以执行其他任务或等待
                printf("No data available for now.\n");
            } else {
                perror("read");
                break;
            }
        } else if (n == 0) {
            // 文件读取完成
            break;
        } else {
            // 处理读取的数据
            printf("Read %zd bytes: %.*s\n", n, (int)n, buffer);
        }
    }

    close(fd);
    return 0;
}

上述代码中的 set_nonblocking 函数用于将文件描述符设置为非阻塞模式。在主循环中,通过不断尝试非阻塞读取,可以实现并发读取的效果。如果当前没有数据可读,则 read 函数会返回 -1,并且 errno 会被设置为 EAGAINEWOULDBLOCK,表示当前没有数据可用,可以执行其他任务或等待。这样,程序可以不阻塞地进行其他操作,实现并发性。

总体而言,非阻塞 I/O 适用于需要高并发、实时响应性的场景,如网络服务器、事件驱动应用等。在正确使用的情况下,非阻塞 I/O 能够提高系统的性能和吞吐量。

unsetunset阻塞I/Ounsetunset

在 Linux 中,阻塞 I/O(Input/Output)是一种默认的 I/O 操作方式,即当应用程序发起 I/O 操作时,如果操作无法立即完成,应用程序将被阻塞(暂停执行)直到操作完成。

阻塞 I/O 操作的示例

  1. 阻塞读取
代码语言:javascript
复制
#include <unistd.h>

char buf[1024];
ssize_t n = read(fd, buf, sizeof(buf));
if (n == -1) {
    // 处理读取错误
} else {
    // 处理读取成功的数据
}

如果文件描述符 fd 上没有可用的数据,read 操作将阻塞等待,直到有数据可读或发生错误。

  1. 阻塞写入
代码语言:javascript
复制
#include <unistd.h>

char buf[1024];
ssize_t n = write(fd, buf, sizeof(buf));
if (n == -1) {
    // 处理写入错误
} else {
    // 处理写入成功
}

如果文件描述符 fd 上的写入缓冲区已满,write 操作将阻塞等待,直到有空间可用或发生错误。

阻塞 I/O 的特点

  1. 等待时间:
    • 阻塞 I/O 操作可能需要等待很长时间,直到操作完成。
  2. 系统资源利用率:
    • 在 I/O 操作等待期间,应用程序将被暂停,系统可以调度其他进程执行。
  3. 适用性:
    • 阻塞 I/O 适用于许多应用程序,尤其是简单的顺序执行程序。

阻塞 I/O 的应用场景

  1. 传统文件操作:
    • 阻塞 I/O 对于传统的文件读写操作是合适的。
  2. 网络通信:
    • 阻塞 I/O 在处理网络通信时常用于简单的场景,但可能在需要实时响应的应用中表现不佳。
  3. 文件系统操作:
    • 阻塞 I/O 适用于对本地文件系统进行的读写和文件操作。

尽管阻塞 I/O 在某些场景下表现良好,但在需要处理大量并发请求、实时响应的场景中,非阻塞 I/O 或异步 I/O 更常被使用。非阻塞 I/O 允许应用程序在 I/O 操作完成之前继续执行其他任务,从而提高系统的响应性。

unsetunset阻塞I/O的优缺点unsetunset

阻塞 I/O(Blocking I/O)是一种默认的 I/O 操作方式,其优点和缺点如下:

优点

  1. 简单易用:
    • 阻塞 I/O 模型相对简单,易于理解和使用,适用于一些简单的顺序执行程序。
  2. 稳定可靠:
    • 阻塞 I/O 在大多数情况下是稳定可靠的,适用于一些不要求高并发、实时响应的应用场景。
  3. 易于调试:
    • 阻塞 I/O 下程序的执行顺序更为明确,对于调试和排错来说相对容易。
  4. 资源占用低:
    • 在 I/O 操作等待期间,应用程序会暂时阻塞,系统可以调度其他进程执行,从而提高系统资源的利用率。

缺点

  1. 低并发性:
    • 阻塞 I/O 在处理多个并发请求时表现不佳,因为一个操作的完成需要等待,可能导致系统资源的浪费。
  2. 实时性差:
    • 阻塞 I/O 操作可能需要很长时间才能完成,对于需要实时响应的应用程序,可能无法满足其要求。
  3. 死锁风险:
    • 在多线程或多进程环境中,阻塞 I/O 操作可能导致死锁,因为一个线程或进程的 I/O 操作可能会阻塞其他线程或进程。
  4. 不适用于事件驱动:
    • 阻塞 I/O 不适用于需要事件驱动、高并发和实时性要求高的应用程序,如网络服务器、实时系统等。
  5. 资源浪费:
    • 在等待 I/O 操作完成的过程中,CPU 和其他系统资源可能被浪费,特别是在处理大量并发请求时。

总体而言,阻塞 I/O 适用于一些简单的应用场景,但在面对高并发、实时性要求高的场景时,非阻塞 I/O 或者异步 I/O 更为常见。这些模型可以更好地利用系统资源,提高系统的并发性和响应性。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-02-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux兵工厂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • unsetunset非阻塞I/Ounsetunset
    • 文件描述符的非阻塞设置
      • 非阻塞 I/O 操作
        • select 和 poll 函数
          • 非阻塞I/O的优缺点
            • 优点
              • 缺点
              • unsetunset非阻塞I/O并发读取unsetunset
              • unsetunset阻塞I/Ounsetunset
                • 阻塞 I/O 操作的示例
                  • 阻塞 I/O 的特点
                    • 阻塞 I/O 的应用场景
                    • unsetunset阻塞I/O的优缺点unsetunset
                      • 优点
                        • 缺点
                        相关产品与服务
                        云服务器
                        云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档