五种IO模型与阻塞IO

news2024/11/26 22:30:33

个人主页:Lei宝啊 

愿所有美好如期而遇


IO本质

我们常说IO就是input,output,也就是输入和输出,但是,他的本质是什么?站在OS角度,站在进程的角度,IO是什么?我们想,输入输出,数据都是保存在内存中,从硬件输入,再输出到硬件上,像scanf,printf,recv,read,write等函数,他们实际上做了什么?其实是等待加拷贝,什么叫等待加拷贝,其实就是说,等待硬件条件满足。我们用recv举例,他就在等待接收缓冲区中有数据,然后将接收缓冲区中的数据拷贝到用户缓冲区中。所以我们说,其实IO的本质就是等待+拷贝

那么什么叫做高效的IO?像我们计算机计算一个简单的加法时,一秒可以计算数亿,但是如果说我们要将每一次计算的结果打印到显示器上,那么可能只有几万,这样的IO显然并不高效,为什么不高效,因为他降低了计算效率,即使结果已经计算出来,但是我们仍然看不到,本质就是因为等待,打印在等待显示器这个硬件资源就绪,而光计算,并不需要等待,所以效率就高,所以高效的IO就是降低等待的时间,等待时间占的比重越低,IO效率越高。

那么什么叫做高效的代码?就是减少IO的比重,因为IO就注定了需要等待硬件资源,注定了会影响效率,第二个就是将等待的时间利用起来,这样也能提高效率。

五种IO模型

  • 1. 阻塞IO,阻塞式等待,资源就绪进行IO。
  • 2. 非阻塞IO, 资源不就绪就直接返回。
  • 3. 信号驱动IO,收到信号进行IO。
  • 4. 多路复用,多路转接。
  • 5. 异步IO。

1和2的区别就在于等待方式不同,什么是多路复用?简单来说,我们传统的IO是等+拷贝,并且一次只能等待一个文件描述符,而多路复用就可以通过系统调用同时等待多个文件描述符,将所有文件描述符等待的时间重叠起来,拷贝工作仍然由我们传统的接口如recv等来完成。异步IO就是说,这些操作全部由内核来完成,用户不用进行IO,我们称用户只要参与了IO,就是同步IO,也就是说,只要用户参与了等或者拷贝,就是同步IO。

这里我们和线程的同步IO做一下区分,线程的同步指的是线程之间的执行具有顺序性,而这里的同步IO指的是只要用户参与了IO就是同步IO。

五种IO方式中最为高效的就是多路复用,当然,因为阻塞IO比较简单,所以使用的还是比较多。

代码实现

接下来我们就简单举个例子来实现一下多路复用。

select系统调用

第一个参数:填写最大fd值+1,中间三个参数,都是fd集合,表示我们想让操作系统监管的fd,最后一个参数是一个结构体指针,这个结构体有两个属性,秒和毫秒,表示select系统调用等待监管的fd集合的时长,当有fd就绪时,这个参数返回,被设置为剩余时长。select返回值为就绪的fd数目。

fd_set类型的变量,实际上是位图,用来标识fd的位置和状态,下面的四个宏,用来对fd_set类型的变量做操作,第一个是移除,第二个是判断存在,第三个是设置,第四个是清空。

#include "Socket.hpp"
#include <vector>

using namespace socket_ns;

const static int N = sizeof(fd_set) * 8;
const static int defaultfd = -1;

class SelectServer
{

public:
    SelectServer(uint16_t port)
        : _port(port), _listensock(make_unique<TcpSocket>()), 
        assist(N, defaultfd)
    {
        Analyze addr("0", _port);
        _listensock->BuildTcpServerSocket(addr);

        assist[0] = _listensock->getfd();
    }

    ~SelectServer() {}

    void Loop()
    {
        while (true)
        {
            fd_set rfds;
            FD_ZERO(&rfds);

            // 将所有合法的fd设置进rfds中
            int maxfd = assist[0];
            for (int i = 0; i < N; i++)
            {
                if (assist[i] == defaultfd)
                    continue;
                FD_SET(assist[i], &rfds);

                if (maxfd < assist[i])
                    maxfd = assist[i];
            }

            timeval timeout = {1, 0};
            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
            switch (n)
            {
            case 0:
                Log(Debug, "timeout...");
                break;
            case -1:
                Log(Error, "select error");
                break;
            default:
                Log(Info, "select fd num: %d", n);
                HandlerEvent(rfds);
                break;
            }
        }
    }

    void HandlerEvent(fd_set &rfds)
    {
        for (int i = 0; i < N; i++)
        {
            // 这里判断守监管的fd是否就绪,监管的fd在assist中
            if (assist[i] == defaultfd)
                continue;
            if (FD_ISSET(assist[i], &rfds))
            {
                if (assist[i] == _listensock->getfd())
                {
                    AcceptClientRequest(); 
                    // listen套接字获取普通套接字加入辅助数组
                }
                else
                {
                    HandlerNormalRequest(i); // 处理普通套接字的请求
                }
            }
        }
    }

    // 参数:已就绪的普通fd的位置
    void HandlerNormalRequest(int pos)
    {
        char buffer[N];
        int n = recv(assist[pos], buffer, sizeof(buffer) - 1, 0);

        if (n > 0)
        {
            cout << buffer << endl;

            string rest = "response: ";
            rest += buffer;
            send(assist[pos], rest.c_str(), rest.size(), 0);
        }
        else
        {
            close(assist[pos]);
            assist[pos] = defaultfd;
        }
    }

    void AcceptClientRequest()
    {
        Analyze an("0", _port);
        sock_addr addr = _listensock->Accept(an); 
        // 通过返回值,我们可以拿到普通socketfd

        int socketfd = addr->getfd();
        if (socketfd < 0)
            return;

        int pos = 1;
        for (; pos < N; pos++)
        {
            if (assist[pos] == defaultfd)
                break;
        }

        if (pos == N)
        {
            close(socketfd);
            Log(Warning, "FULL");
            return;
        }
        else if (pos < N)
        {
            assist[pos] = socketfd;
            Log(Info, "AcceptClientRequest Set Success");
        }
    }

private:
    uint16_t _port;
    unique_ptr<Socket> _listensock;

    vector<int> assist;
};

select实现的多路复用,是有缺陷的,因为它能够等待的fd是有上限的,在博主的ubuntu下,他是1024个bit位,也就是说,最多能够同时等待1024个fd。

再一个,每一次,对select的参数来说,都需要重新设置,而poll解决了这两个问题,但是这里我们不再多谈,后面我们会讲解epoll。

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

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

相关文章

申请专利需要准备哪些材料?

申请专利需要准备哪些材料&#xff1f;

代码之外的生存指南——自我营销

你是否有去过酒吧、夜店看过驻场乐队的演出&#xff1f; 你到了那里面听过之后你会发现那些乐队的演唱水平丝毫不亚于原唱的艺术家们&#xff0c;都很有才华&#xff1b; 你有没有想过【为什么这些驻场乐队就只能在那小小的夜店里做驻唱演出&#xff0c;每天疲于奔命&#xff0…

图综述-GGNN详解

A Survey of Geometric Graph Neural Networks:Data Structures, Models and Applications 本文主要介绍了在化学领域的分子设计和预测任务中&#xff0c;如何利用几何图神经网络&#xff08;Geometric Graph Neural Networks&#xff0c;简称GGNN&#xff09;来处理具有几何信…

怎样可以撰写出一篇优质软文呢?

现在这个互联网飞速发展的时代&#xff0c;软文推广已经逐渐变成了现在很多企业和品牌的推广宣传方式了&#xff0c;虽然软文推广操作起来很简单&#xff0c;但是想要做好没那么简单&#xff0c;软文稿件的质量和推广的流量更是息息相关。 好的软文不止可以让转化更高&#xff…

不容忽视!猫咪浮毛问题严重,宠物空气净化器教你一招清理

拥有一只可爱的猫咪&#xff0c;无疑是家庭中温馨与欢乐的源泉&#xff0c;但同时&#xff0c;宠物的毛发管理也成为了不少家庭面临的日常挑战。每当家中四处飘散着它们细腻的毛发&#xff0c;尤其是拥抱过后&#xff0c;衣物上不经意间沾满了轻盈的浮毛&#xff0c;宠物们随着…

【Material-UI】按钮组件的限制及解决方法详解

文章目录 一、ButtonBase 组件与禁用状态的限制1. 默认行为&#xff1a;pointer-events: none示例代码 2. 显示 not-allowed 光标的解决方案方法一&#xff1a;纯 CSS 解决方案方法二&#xff1a;DOM 结构变化 3. 工具提示&#xff08;Tooltip&#xff09;与禁用状态 二、其他常…

Javascript——原始数据类型的自动装箱

自动装箱 聊个例子介绍例子 聊个例子 ‘asd’.length //这其中是怎么执行的在 JavaScript 中&#xff0c;字符串是原始数据类型&#xff08;primitive data type&#xff09;&#xff0c;但它们表现得像对象&#xff0c;因为它们有属性和方法。当你对一个字符串使用 .length 属…

原型图绘制技巧

针对于 Axure RP绘图软件。 1、拉辅助线 目的&#xff0c;确定画布大小尺寸从上面和左面的刻度尺上&#xff0c;点击鼠标&#xff0c;拖动&#xff0c;就可以拉出一条线。 2、画布底模设为组件 右键转换为母版&#xff0c;方便后续其他页面使用 3、按钮 按钮字体不要太大&am…

【Material-UI】Button 组件自定义详解

文章目录 一、自定义 Button 组件的基础1. 基于 styled 方法的自定义2. styled 方法详解3. 覆盖默认样式 二、高级自定义技巧1. 主题色彩与调色板2. 无障碍性与响应式设计 三、集成与测试1. 集成到项目中2. 测试自定义样式 四、总结 在使用 Material-UI 开发 Web 应用时&#x…

动态贝叶斯网络DBN介绍

动态贝叶斯网络DBN介绍 1. 引言2. 贝叶斯网络与动态贝叶斯网络2.1 贝叶斯网络简介2.2 动态贝叶斯网络详细介绍2.3 两种网络对比 3. 搭建动态贝叶斯网络的方法3.1 定义网络结构3.2 参数学习3.3 推理3.4 结构学习和参数学习的方法3.4.1 结构学习3.4.2 参数学习 4. 总结5. 参考文献…

【医学影像】无痛安装mamba

去年编辑的一个帖子。摆了一段时间后重新回归&#xff0c;发送一下作为状态分界线。 很癫狂的体验&#xff0c;man&#xff0c;what can i say&#xff01; issue查看我的狗急跳墙状态 1.确定版本 cuda nvcc -Vpython python --versiontorch pip show torch2.下载对应版本…

电燃灶(电焰灶)、燃气灶、电磁炉,谁更契合中国人的烹饪习惯?

中国人的烹饪文化源远流长&#xff0c;丰富多样的烹饪方式和独特的口味需求造就了对炉灶的严格要求。在现代厨房中&#xff0c;电燃灶&#xff08;电焰灶&#xff09;、燃气灶和电磁炉成为了常见的选择。那么&#xff0c;究竟哪一种更适合中国人的烹饪习惯呢&#xff1f; 一、明…

[Paddle] 从零安装 Paddle 框架

1 安装前准备 1.1 安装环境 本机安装环境如下&#xff1a; 运行环境操作系统Ubuntu 22.04.4 LTS (Jammy Jellyfish)CPUIntel Core™ i5-12400显卡NVIDIA GeForce RTX 4090 1.2 验证 GPU 是否为 NVIDIA GPU 在命令行输入以下代码&#xff0c;以验证您的 GPU 是否是 NVIDIA …

零基础报考软考只是为了证书,应该报考初级还是中级呢?

证书的价值仍然非常吸引人~ 软考不仅是技术水平考核&#xff0c;也是评定职称资格的考试&#xff0c;是评定职称的主要条件。国有企业和事业单位的员工可以凭借软考中级以上的证书申请中级职称、副高级职称或者高级职称。此外&#xff0c;软考对于提升职位和加薪有着重要的作用…

嘉立创EDA专业版本创建自定义元件和封装

嘉立创EDA专业版本创建自定义元件和封装 1.新建封装2.新建元件1.新建封装 然后保存就可以了 2.新建元件 这里主要添加新建的封装

DisplayFusion显示器使用好助手

目录 一、软件基本信息 a) 官网&#xff1a; b) 下载&#xff1a; c) 功能概述 二、软件安装 三、几个应用场景 1、显示器分割 2、应用发送到桌面 3、桌面壁纸设置 4、任务栏设置 5、其它 四、授权 初识DisplayFusion还是在2017年&#xff0c;当时有个LED…

CSP-J复赛 模拟题4

1. 删数游戏: 题目描述 两名同学在黑板上做删数游戏&#xff0c;游戏规则如下&#xff1a; 两名同学先一起在黑板上写了n个数字&#xff0c;同学A先擦掉一个数字&#xff0c;之后同学B再擦掉一个数字&#xff0c;轮流进行&#xff0c;直到黑板上只剩下最后一个数字&#xff…

Vue脚手架的安装(超详细篇,保姆级教程)

一、环境安装 1.软件下载 官网&#xff1a;https://github.com/coreybutler/nvm-windows/releases 官网往下滑&#xff0c;找到这个nvm-setup.zip,然后进行下载 2.安装 下载后&#xff0c;双击进行安装&#xff0c;注意安装目录不要出现中文和空格 安装后&#xff0c;打开cm…

时间序列分析基础20问

时间序列分析是一类特殊的数据分析问题。它是对连续间隔离散时间序列的观察。在现实世界中的应用包括天气预测模型、股市预测等。 本文通过20个问题&#xff0c;深入解析时间序列分析的基础概念和方法。 1. 什么是时间序列数据&#xff1f; 时间序列数据是按照时间顺序排列的、…

谷粒商城实战笔记-129-商城业务-商品上架-nested数据类型场景

文章目录 扁平化处理扁平化处理导致的检索问题 解决方案&#xff1a;使用 nested 结构 在es的数据类型中有一个nested类型&#xff0c;本讲将重点讨论这个类型。 扁平化处理 PUT my_index/doc/1 {"group" : "fans","user" : [{"first&quo…