I/O 多路复用:`select`、`poll`、`epoll` 和 `kqueue` 的区别与示例

I/O 多路复用是指在一个线程内同时监控多个文件描述符(File Descriptor, FD),以便高效地处理多个 I/O 事件。在 UNIX/Linux 和 BSD 系统中,selectpollepollkqueue 都是实现 I/O 多路复用的系统调用。它们各有特点,适合不同的应用场景。本文将详细介绍它们的用法、优缺点,并附上相应的代码示例。
在这里插入图片描述

1. select

概述

select 是最早的 I/O 多路复用系统调用之一,广泛支持于各类操作系统中。它允许程序同时监视多个文件描述符,但有最大数量的限制(通常是 1024 个文件描述符)。

优点

  • 简单,适用性广泛。
  • 支持几乎所有 UNIX 类操作系统。

缺点

  • 文件描述符数量有限制。
  • 每次调用都需要重新设置文件描述符集合,效率较低。

使用示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <unistd.h>int main() {fd_set readfds;struct timeval timeout;int ret;// 初始化文件描述符集合FD_ZERO(&readfds);FD_SET(STDIN_FILENO, &readfds);// 设置超时时间timeout.tv_sec = 5;timeout.tv_usec = 0;printf("Waiting for input, timeout in 5 seconds...\n");// 调用 select 函数,监控文件描述符ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &timeout);if (ret == -1) {perror("select");exit(EXIT_FAILURE);} else if (ret == 0) {printf("Timeout occurred! No data after 5 seconds.\n");} else {if (FD_ISSET(STDIN_FILENO, &readfds)) {char buffer[1024];read(STDIN_FILENO, buffer, sizeof(buffer));printf("Data read: %s\n", buffer);}}return 0;
}

解释

在上述代码中,我们使用 select 函数监听标准输入 (STDIN_FILENO) 的可读性。如果用户在 5 秒内没有输入,程序会超时并退出。

2. poll

概述

poll 作为 select 的改进版本,消除了文件描述符数量的限制。它通过一个 pollfd 数组来管理多个文件描述符,解决了 select 的一些局限性。

优点

  • 没有文件描述符数量限制。
  • API 比较简洁,避免了 select 需要重置文件描述符集合的问题。

缺点

  • select 一样,每次调用仍需遍历整个文件描述符集合。

使用示例

#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#include <unistd.h>int main() {struct pollfd fds[1];int ret;// 设置文件描述符和事件fds[0].fd = STDIN_FILENO;fds[0].events = POLLIN;printf("Waiting for input, timeout in 5 seconds...\n");// 调用 poll 函数,设置 5 秒超时ret = poll(fds, 1, 5000);if (ret == -1) {perror("poll");exit(EXIT_FAILURE);} else if (ret == 0) {printf("Timeout occurred! No data after 5 seconds.\n");} else {if (fds[0].revents & POLLIN) {char buffer[1024];read(STDIN_FILENO, buffer, sizeof(buffer));printf("Data read: %s\n", buffer);}}return 0;
}

解释

这里的代码使用 poll 来监控标准输入的可读性。与 select 类似,它设置了一个 5 秒的超时时间,但使用 poll 可以处理更多的文件描述符。

3. epoll

概述

epoll 是 Linux 特有的系统调用,它专门为处理大量文件描述符而设计,性能远优于 selectpollepoll 使用一个事件通知机制,避免了每次调用时遍历整个文件描述符集合。

优点

  • 高效,适合处理大量文件描述符。
  • 不需要每次遍历整个文件描述符集合。

缺点

  • 仅支持 Linux 系统。

使用示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <unistd.h>int main() {int epfd = epoll_create1(0);struct epoll_event event, events[1];int ret;if (epfd == -1) {perror("epoll_create1");exit(EXIT_FAILURE);}// 设置事件event.events = EPOLLIN;event.data.fd = STDIN_FILENO;if (epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event) == -1) {perror("epoll_ctl");exit(EXIT_FAILURE);}printf("Waiting for input, timeout in 5 seconds...\n");// 调用 epoll_wait,等待事件ret = epoll_wait(epfd, events, 1, 5000);if (ret == -1) {perror("epoll_wait");exit(EXIT_FAILURE);} else if (ret == 0) {printf("Timeout occurred! No data after 5 seconds.\n");} else {if (events[0].data.fd == STDIN_FILENO) {char buffer[1024];read(STDIN_FILENO, buffer, sizeof(buffer));printf("Data read: %s\n", buffer);}}close(epfd);return 0;
}

解释

在这个示例中,我们使用 epoll 来监控标准输入。epoll_create1 创建了一个 epoll 实例,随后通过 epoll_ctl 添加文件描述符。epoll_wait 用来等待事件发生,效率远高于 selectpoll

4. kqueue

概述

kqueue 是 BSD 系统(包括 macOS)中的高效 I/O 事件通知机制。与 epoll 类似,kqueue 使用事件通知的机制来避免每次遍历整个文件描述符集合。

优点

  • 高效,适合处理大量 I/O 事件。
  • 支持 BSD 系统。

缺点

  • 仅支持 BSD 系统(包括 macOS)。

使用示例

#include <stdio.h>
#include <stdlib.h>
#include <sys/event.h>
#include <sys/time.h>
#include <unistd.h>int main() {int kq = kqueue();struct kevent change, event;int ret;if (kq == -1) {perror("kqueue");exit(EXIT_FAILURE);}// 设置事件EV_SET(&change, STDIN_FILENO, EVFILT_READ, EV_ADD, 0, 0, NULL);printf("Waiting for input, timeout in 5 seconds...\n");// 调用 kevent,设置 5 秒超时struct timespec timeout = {5, 0};ret = kevent(kq, &change, 1, &event, 1, &timeout);if (ret == -1) {perror("kevent");exit(EXIT_FAILURE);} else if (ret == 0) {printf("Timeout occurred! No data after 5 seconds.\n");} else {if (event.ident == STDIN_FILENO) {char buffer[1024];read(STDIN_FILENO, buffer, sizeof(buffer));printf("Data read: %s\n", buffer);}}close(kq);return 0;
}

解释

在 BSD 系统中,kqueue 提供了一种高效的 I/O 事件通知机制。该代码监控标准输入,超时时间为 5 秒,使用 kevent 等待事件发生。

5. 总结

特性selectpollepollkqueue
支持的平台Unix/Linux/BSDUnix/Linux/BSDLinuxBSD/macOS
文件描述符限制有限制(1024)无限制无限制无限制
效率较低较低
扩展性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/52805.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

el-input设置type=‘number‘和v-model.number的区别

el-input设置typenumber’与设置.number修饰符的区别 1. 设置type‘number’ 使用el-input时想收集数字类型的数据&#xff0c;我们首先会想到typenumber&#xff0c;设置完type为number时会限制我们输入的内容只能为数字&#xff0c;不能为字符/汉字等非数字类型的数值&…

房产销售系统开发:SpringBoot技术要点

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于房产销售系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了房产销售系统&#xff0c;它彻底改变了过去传统的…

基于Prometheus和Grafana的现代服务器监控体系构建

构建基于Prometheus和Grafana的现代服务器监控体系是一个非常有效的方式来监控服务器性能、资源利用率和应用程序健康状况。以下是一些步骤和指南&#xff0c;帮助您构建这样一个监控体系&#xff1a; 1. **安装和配置Prometheus**&#xff1a; - 下载并安装Prometheus&…

性能诊断的方法(五):架构和业务诊断

关于性能诊断的方法&#xff0c;我们可以按照“问题现象—直接原因—问题根源”这样一个思路去归纳。我们先从问题的现象去入手&#xff0c;包括时间的分析、资源的分析和异常信息的分析。接下来再去分析产生问题现象的直接原因是什么&#xff0c;这里我们归纳了自上而下的资源…

外观模式详解:如何为复杂系统构建简洁的接口

&#x1f3af; 设计模式专栏&#xff0c;持续更新中 欢迎订阅&#xff1a;JAVA实现设计模式 &#x1f6e0;️ 希望小伙伴们一键三连&#xff0c;有问题私信都会回复&#xff0c;或者在评论区直接发言 外观模式 外观模式&#xff08;Facade Pattern&#xff09;为子系统中的一组…

linux系统安装miniconda3

一、下载minconda3 下载地址&#xff1a;https://docs.conda.io/en/latest/miniconda.html 一般国内访问比较困难&#xff0c;可到清华软件镜像站 Index of /anaconda/miniconda/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 需要特别注意自己的下载版本和自己的…

初识爬虫2

requests学习&#xff1a; 小技巧&#xff0c;如果你用的也是pycharm&#xff0c;对于控制台输出页面因为数据很长一行&#xff0c;不方便进行查看&#xff0c; 可以让它自动换行&#xff1a; 1.requests文档阅读学习链接&#xff1a;快速上手 — Requests 2.18.1 文档 需掌…

如何利用 Redis 列表实现一个简单的任务调度系统?

以下是利用 Redis 列表实现一个简单任务调度系统的步骤: 一、任务存储 定义任务格式 每个任务可以是一个包含任务相关信息的字符串或者 JSON 对象。例如,任务可以包含任务 ID、任务执行的函数名、执行参数、执行时间等信息。例如,一个简单的任务可以表示为{"id":…

【运维监控】Prometheus+grafana监控zookeeper运行情况

运维监控系列文章入口&#xff1a;【运维监控】系列文章汇总索引 文章目录 一、prometheus二、grafana三、prometheus集成grafana监控zookeeper1、修改zookeeper配置2、修改prometheus配置3、导入grafana模板4、验证 本示例通过zookeeper自带的监控信息暴露出来&#xff0c;然后…

基于imx6ull平台opencv的图像采集和显示屏LCD显示功能(带Qt界面)

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 验证功能一、概述 本文档是针对imx6ull平台opencv的图像采集和显示屏LCD显示功能,创建Qt工程,在工程里面通过点击按钮,实现opencv通过摄像头采集视频图像,将采集的视频图像送给显示屏LCD进…

LabVIEW编程快速提升的技术

在LabVIEW程序员的成长过程中&#xff0c;很多技术和概念看似简单、常用&#xff0c;但真正掌握并能熟练运用&#xff0c;往往需要踏踏实实的实践与积累。没有什么是能够一蹴而就的&#xff0c;唯有通过不断的专注与深入&#xff0c;才能获得显著的提升。要想在LabVIEW开发上取…

SSM框架学习(三、MyBatis实践:提高持久层数据处理效率)

目录 一、Mybatis简介 1.简介 2.持久层框架对比 3.快速入门&#xff08;基于Mybatis3方式&#xff09; 4.ibatis方式的实现和原理 5.ibatis与mybatis之间的关系 二、Mybatis基本使用 1.向 sql 语句传参 &#xff08;1&#xff09;mybatis日志输出配置 &#xff08;2&…

为什么矩阵特征值之和等于主对角线元素之和,特征值乘积等于行列式值

首先给出特征值和特征向量的定义。 设A是n阶矩阵&#xff0c;如果数λ和n维非零向量x使关系式 Axλx &#xff08;1&#xff09; 成…

JavaScript知识点3

目录 1.JavaScript中有多少个线程&#xff1f; 2.如何判断一个对象是不是空对象&#xff1f; 3.什么事JavaScript时间死区&#xff1f; 4.什么是JSON stringify&#xff1f; 1.JavaScript中有多少个线程&#xff1f; JavaScript中的主线程负责执行代码、处理事件和更新用户…

最大余额法,解决百分比计算相加不等于100%(扇形/饼图百分比使用的此算法)

在开发项目的过程中有时候需要进行计算百分比&#xff0c;例如计算饼状图百分比。有时候在计算的过程中常规四舍五入计算会发生所有计算的值相加不等于100%的情况 这是 get_percent_value 函数的 JavaScript 版本&#xff1a; /*** 最大余额法&#xff0c;解决百分比计算相加不…

什么是蜘蛛池?有什么作用

在网络爬虫的世界里&#xff0c;蜘蛛池&#xff08;Spider Pool&#xff09;是一个专门用于管理和维护大量爬虫的系统。它为爬虫提供了一个集中的工作环境&#xff0c;使得爬虫能够更高效、更稳定地进行数据抓取。本文将探讨蜘蛛池的概念、组成以及它在现代网络爬虫技术中的作用…

微信小程序使用canvas画图保存图片到手机相册

微信小程序要实现使用canvas绘制一个图&#xff0c;然后保存到手机相册 **最终效果&#xff1a;**实现生成以下图片 一、初始化canvas // wxml页面设置canvas标签 <canvas style"width: {{windowW}}px; height: {{windowH}}px;" disable-scrolltrue canvas-id&…

llvm后端之函数栈帧

llvm后端之函数栈帧 引言1 目标扩展实现1.1 emitPrologue和emitEpilogue1.2 storeRegToStackSlot和loadRegFromStackSlot 2 寄存器存栈与恢复 引言 llvm后端在物理寄存器分配后、指令发射前会调用PEI这个pass来生成函数栈帧的创建与销毁。 1 目标扩展实现 在target下&#x…

使用PyTorch进行图像风格迁移:基于VGG19实现

图像风格迁移&#xff08;Neural Style Transfer, NST&#xff09;是深度学习中一个令人着迷的应用&#xff0c;它能够将一张图像的风格应用到另一张图像上。例如&#xff0c;能够将梵高的画风应用到一张普通照片上。本文将详细解释如何使用PyTorch进行风格迁移&#xff0c;逐步…

解决el-table排序sortable只排序当前页问题

el-table-column中添加sortable只是让每页数据单独排序&#xff0c;没有把所有数据进行排序&#xff0c;可以通过sort-change事件解决。 1、首先在需要排序的列上加sortable“custom” <el-table-columnprop"date"label"日期"width"180"sort…