IO模型介绍

一、理解IO

网络通信的本质就是进程间通信,进程间通信本质就是IO

TCP中的IO接口:read / write / send / recv,本质都是:等 + 拷贝

所以IO的本质就是:等 + 拷贝

那么如何高效的IO?

减少“等”在单位时间的比重

二、5种IO模型

同步IO就是亲自参与IO过程

1、阻塞IO

等到数据就绪才会拷贝。所有套接字(文件描述符)一开始都是默认阻塞IO

2、非阻塞IO

非阻塞 IO: 如果内核还未将数据准备好 , 系统调用仍然会直接返回 , 并且返回EWOULDBLOCK错误码。但是其实不是数据错误,只是数据没就绪。
非阻塞 IO 往往需要程序员循环的方式反复尝试读写文件描述符 , 这个过程称为 轮询 这对 CPU 来说是较大的浪费 , 一般只有特定场景下才使用。

3、信号驱动IO

内核将数据准备好的时候 , 使用 SIGIO 信号通知应用程序进行 IO操作。

4、多路转接IO

用select解放recvfrom,把等和拷贝完全分开,能够同时等待多个文件描述符的就绪状态。

5、异步IO

应用进程让OS自己等和拷贝,OS做完之后告诉进程,应用进程再对数据进行处理。

三、非阻塞IO

1、介绍函数

一开始文件描述符都是默认阻塞,用函数实现非阻塞

功能:
 
(1)复制一个现有的描述符( cmd=F_DUPFD)
(2)获得/ 设置文件描述符标记 (cmd=F_GETFD F_SETFD)
(3)获得/ 设置文件状态标记 (cmd=F_GETFL F_SETFL)
(4)获得/ 设置异步 I/O 所有权 (cmd=F_GETOWN F_SETOWN)
(5)获得/ 设置记录锁 (cmd=F_GETLK,F_SETLK F_SETLKW)

2、函数实现非阻塞

#include<iostream>
#include<unistd.h>
#include<fcntl.h>
using namespace std;void SetNonBlock(int fd)
{// 获取文件状态标记int fl = fcntl(fd, F_GETFL);if(fl < 0){cout << "fcntl error" << endl;return;}// 文件状态标记加上非阻塞等待fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}

3、实现非阻塞轮询

#include<iostream>
#include<cstdio>
#include<unistd.h>
#include"Command.hpp"
using namespace std;int main()
{char buffer[1024];// 设置非阻塞文件描述符SetNonBlock(0);while(1){printf("Enter#: ");// 立即刷新到显示器fflush(stdout);ssize_t n = read(0, buffer, sizeof buffer);if(n > 0){buffer[n] = 0;printf("echo: %s", buffer);}else if(n == 0){printf("read done\n");break;}else{// 非阻塞轮询虽然数据没准备好不是错误,但是会以错误返回// 所以判断错误码确认是底层不就绪还是出错if(errno == EWOULDBLOCK){sleep(1);cout << "数据没就绪" << endl;// 非阻塞时做其他事情continue;}else if(errno == EINTR){continue;}else{perror("read");break;}}}return 0;
}
收到中断信号错误码是EINTR,继续轮询即可。

四、多路转接

1、多路转接思路

只聚焦于等,等待fd中新事件就绪,通知程序员时间就绪,进行IO拷贝。

事件:只有OS才知道到文件描述符的缓冲区是否有读写的能力。OS底层有数据,读事件就绪。OS底层有空间,写事件就绪。

2、方案一:select

select 系统调用是用来让我们的程序监视多个文件描述符的状态变化的。 程序会停在 select 这里等待,直到被监视的文件描述符有一个或多个发生了状态改变。 只负责等,不负责拷贝。

nfds:传入的文件描述符最大值 + 1,不是传入的文件描述符个数。

timeout:结构体 timeval 里面有秒和毫秒,精度是毫秒,输入输出型参数,微秒级别时间戳结构体指针。

timeval timeout = {3, 0}; 3秒内阻塞等待fd新事件,有就绪就返回timeout剩余时间,3秒没有新事件就非阻塞轮询。

timeval timeout = {0, 0}; 直接非阻塞轮询

timeval timeout = nullptr; 直接阻塞等待

返回值:大于0,有几个文件描述符就绪。等于0,等待超时。小于0,select出错。

fd_set:文件描述符集,位图结构,比特位位置表示几号文件描述符,比特位内容表示是否关心fd事件 / fd事件是否发生。

readfds:输入输出型,只关心读事件。输入:用户告诉OS,要关心fd_set里面的读事件。输出:OS告诉用户,有哪些fd读事件就绪。

writefds:输入输出型,只关心写事件。输入:用户告诉OS,要关心fd_set里面的写事件。输出:OS告诉用户,有哪些fd写事件就绪。

exceptfds:输入输出型,只关心异常事件。输入:用户告诉OS,要关心fd_set里面的异常事件。输出:OS告诉用户,有哪些fd异常事件就绪。

对fd_set类型位图操作

我们不能自己对位图操作,要调用接口。

注意:

首先我们要维护多个文件描述符,所以就要有一个数组来保存合法fd。

而且三个参数都是输入输出型参数,这就意味着用户告诉内核要关心的事件内核给用户返回关心事件的情况这两种情况都是由同一个 struct fd_set 传达的,这就要每次使用时重置。

事件就绪后要用循环检测处理事件。

代码实现(先只展示读文件描述符)

#pragma once
#include <iostream>
using namespace std;
#include "Socket.hpp"
using namespace socket_ns;
#include "log.hpp"
using namespace log_ns;
#include "inetAddr.hpp"
class SelectServer
{const static int gnum = sizeof(fd_set) * 8;const static int gdefaultfd = -1;public:SelectServer(uint16_t port): _port(port), _listensockfd(make_unique<TcpSocket>()){_listensockfd->BuildListenSocket(_port);}void InitServer(){for (int i = 0; i < gnum; i++){fd_array[i] = gdefaultfd;}// 默认直接添加fd_array[0] = _listensockfd->Sockfd();}// listen套接字获取到新连接,即读事件就绪void Accepter(){// listen套接字读事件就绪// 已经就绪,绝对不会接收阻塞InetAddr addr;int connfd = _listensockfd->Accepter(&addr);if (connfd > 0){LOG(DEBUG, "get a new link, client info %s:%d\n", addr.Ip().c_str(), addr.Port());// 新连接已经来了,但是不能直接读,可能会阻塞// OS清楚底层connfd数据是否就绪,要select// 把新的connfd添加给select,即添加到fd_arraybool flag = false;for (int pos = 1; pos < gnum; pos++){if (fd_array[pos] == gdefaultfd){fd_array[pos] = connfd;flag = true;LOG(INFO, "add %d to fd_array success!\n", connfd);break;}}// 没有空余的空间存储新的文件描述符if (flag == false){LOG(WARNING, "select is full\n");close(connfd);}}else{return;}}// 普通套接字读事件就绪,进行IOvoid HandlerIO(int connfd){// 普通套接字读事件就绪char buffer[1024];// 不会阻塞ssize_t n = recv(connfd, buffer, sizeof buffer - 1, 0);if (n > 0){buffer[n] = 0;cout << "client say# " << buffer << endl;string echo_str = "[server echo info] ";echo_str += buffer;// 可以直接写,任何一个文件描述符一开始获取时两个缓冲区都是空的// 这就意味着,一开始读事件一定不就绪,但是写事件一定就绪send(connfd, echo_str.c_str(), echo_str.size(), 0);}else if (n == 0){LOG(INFO, "client quit....\n");// 关闭fdclose(connfd);// select不要再关心fd,即移除fdconnfd = gdefaultfd;}else{LOG(ERROR, "recv error\n");// 关闭fdclose(connfd);// select不要再关心fd,即移除fdconnfd = gdefaultfd;}}// 事件就绪,开始处理void HandlerEvent(fd_set &rfds){// 事件派发for (int i = 0; i < gnum; i++){if (fd_array[i] == gdefaultfd)continue;// fd合法,但不知道是不是就绪if (FD_ISSET(fd_array[i], &rfds)){// 读事件就绪if (_listensockfd->Sockfd() == fd_array[i]){Accepter();}else{HandlerIO(fd_array[i]);}}}}void Loop(){while (1){// 1.文件描述符集初始化fd_set rfds;FD_ZERO(&rfds);int max_fd = gdefaultfd;// 2.合法fd添加到rfdsfor (int i = 0; i < gnum; i++){if (fd_array[i] != gdefaultfd){FD_SET(fd_array[i], &rfds);}// 获取最大文件描述符值if (max_fd < fd_array[i])max_fd = fd_array[i];}// 3.开始select所有合法fdstruct timeval timeout = {3, 0};// 当前不能直接accept listensocket 因为函数的本质是把套接字看成文件描述符// 今天里面的函数没有改造,本质就是只关心新连接的到来,是读事件就绪,阻塞等待int n = select(max_fd + 1, &rfds, nullptr, nullptr, nullptr /*&timeout*/);switch (n){case 0:LOG(DEBUG, "time out, %d.%d\n", timeout.tv_sec, timeout.tv_usec);break;case -1:LOG(ERROR, "select error\n");break;default:LOG(INFO, "eventr eady, n = %d\n", n);HandlerEvent(rfds);PrintDebug();break;}}}void PrintDebug(){cout << "fd list: ";for (int i = 0; i < gnum; i++){if (fd_array[i] != gdefaultfd){cout << fd_array[i] << " ";}}cout << endl;}~SelectServer(){}private:uint16_t _port;unique_ptr<Socket> _listensockfd;int fd_array[gnum]; // 辅助数组,保存合法fd
};

思路:一开始创建 SelectServer 对象时创建监听套接字,InitServer 函数把监听套接字作为要维护的第一个文件描述符。然后 Loop 函数作为入口函数,循环检测每一次读文件描述符集的变化,用于解决事件函数 HandlerEvent,HandlerEvent 函数做事件派发的工作,如果是监听套接字读事件就绪,那就是有新的连接来了,这时调用 Accepter 函数(找到维护文件描述符的数组中空的位置填入新的连接描述符 connfd),如果是普通的连接套接字读事件就绪,就进行普通IO事件,调用HandlerIO 函数(收数据,然后写回应答,可以直接写,任何一个文件描述符一开始获取时两个缓冲区都是空的。这就意味着,一开始读事件一定不就绪,但是写事件一定就绪。)到这里 HandlerEvent 函数结束,Loop 函数也结束了。

select 优缺点:

优点:能等待多个文件描述符。

缺点:每次调用 select 要重新用 fd_array 设置合法文件描述符进文件描述符集

每次调用 select 要把 fd 从用户态发到内核态,开销大(多路转接无法避免)

每次调用 select 要遍历 fd_array :重新设置 fd_set 时,事件派发时遍历检测 fd 是否就绪,为新连接找到合适的 fd_array 位置

select 存储的文件描述符太少

3、方案二:poll

解决了文件描述符太少和每次都要重新设置 fd_set 问题。

返回值:大于0,有几个文件描述符就绪。等于0,等待超时。小于0,poll出错。

timeout:以毫秒为单位的超时时间,只作输入。等于0,非阻塞等待。小于0,阻塞等待。大于0,先阻塞等待,有新事件就返回,没有就超时阻塞等待。

struct pollfd:

fd:要关心的文件描述符

events:用户到内核,告诉内核你要关心的指定文件描述符的指定事件。

revents:内核到用户,内核返回给用户关心的指定文件描述符的指定事件已经就绪。

因为事件被定义成了宏,所以多个事件的添加用 | 来连接,判断返回的事件里面有无指定事件用 & 判断。

事件介绍:

fds:数组 struct pollfd 的起始位置指针。

nfds:数组元素个数,理论上无限多。

poll 优缺点:

优点:包含了 events 和 revents 分别表示用户到内核和内核到用户,所以解决每次都要重新设置 fd_set 问题。poll没有最大文件描述符的限制,只取决于用户想创建多少个 pollfd

缺点:底层是OS帮我们做的循环检测,还是要遍历。每次调用要把 fd 从用户态拷贝到内核态。

4、方案三:epoll

(1)接口介绍

a、epoll创建 

返回值:如果创建成功返回文件描述符,失败返回-1

size:废弃字段,填大于0就行。

b、epoll控制 用户 -> 内核

epfd:epoll_create返回的文件描述符

op:操作epoll的选项:

EPOLL_CTL_ADD:增加一个特定描述符fd的特定事件。

EPOLL_CTL_MOD:修改一个特定描述符fd的特定事件。

EPOLL_CTL_DEL:删除一个特定描述符fd的特定事件。

fd:op中的特定描述符,上层关心的文件描述符。

struct epoll_event:

epoll_data是枚举类型,四选一,一般选fd

events可以选择:

event:一般先创建一个struct epoll_event,初始化后取地址做参数。当op == EPOLL_CTL_DEL时,event是nullptr,即无事件。

c、epoll等待 内核 -> 用户

events:一般创建一个struct epoll_event数组来接收内核告诉用户有多少个事件就绪。

maxevents:struct epoll_event数组大小

返回值:大于0,有几件事件就绪。等于0超时。小于0出错。

(2)原理

检测底层是否有事件就绪,如果有红黑树中关心的事件就绪,就形成节点了链入到就绪队列,epoll_wait 会将就绪事件一次严格按顺序放入用户定义的缓冲区,上层用户拿到的一定是有序的有效的待处理事件。

(3)内核级理解

所以我们就理解为什么epoll_create返回的是文件描述符了,通过文件描述符就能找到最后的epoll模型。

但是我们还要深入理解一下就绪队列和红黑树里面的节点关系,因为我们明显发现其实节点里面存储的数据应该不会有大差别(实际上是没有差别)

Linux内核中链表实现

所以其实不同于以前的节点,内核中实现的节点只有连接节点,每一个不同的以链表为基础的存储节点只要带上通用的连接节点就行,数据自己定。

知道link结构体怎么算出task_struct结构体的起始地址?

(4)epoll代码案例

#pragma once
#include <string>
#include <iostream>
using namespace std;
#include "Socket.hpp"
using namespace socket_ns;
#include "log.hpp"
using namespace log_ns;
#include "inetAddr.hpp"
#include <sys/epoll.h>class EpollServer
{const static int num = 128;const static int size = 128;public:EpollServer(uint16_t port): _port(port), _listensock(make_unique<TcpSocket>()){_listensock->BuildListenSocket(port);_epfd = ::epoll_create(size);if (_epfd < 0){LOG(FATAL, "epoll create error\n");exit(1);}LOG(INFO, "epoll create success, epfd:%d\n", _epfd);}void InitServer(){// 先添加listen套接字struct epoll_event ev;// 新连接到来读事件就绪ev.events = EPOLLIN;ev.data.fd = _listensock->Sockfd();int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock->Sockfd(), &ev);if (n < 0){LOG(FATAL, "epoll create error\n");exit(2);}LOG(INFO, "epoll_ctl success, add new sockfd:%d\n", _listensock->Sockfd());}string EventsToString(uint32_t events){string eventstr;if (events & EPOLLIN)eventstr = "EPOLLIN";if (events & EPOLLOUT)eventstr += "|EPOLLOUT";return eventstr;}void Accepter(){InetAddr addr;int connfd = _listensock->Accepter(&addr);if (connfd < 0){LOG(ERROR, "accept error\n");return;}LOG(INFO, "get a new link, %d, client info:%s:%d\n", connfd, addr.Ip(), addr.Port());// 新连接不能读,但是一定能写// 两个缓冲区都是空,读事件一定不就绪// 新连接connfd放入epollstruct epoll_event ev;ev.data.fd = connfd;ev.events = EPOLLIN;::epoll_ctl(_epfd, EPOLL_CTL_ADD, connfd, &ev);LOG(INFO, "epoll_ctl success, add new sockfd:%d\n", connfd);}void HandlerIO(int fd){char buffer[4096];int n = recv(fd, buffer, sizeof buffer - 1, 0);if (n > 0){buffer[n] = 0;cout << buffer;}else if (n == 0){LOG(INFO, "client quit, close fd,:%d\n", fd);// 从epoll中移除fd,这个fd必须健康合法,所以先移除后关闭epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);// 关闭fd::close(fd);}else{LOG(ERROR, "recv error, close fd,:%d\n", fd);// 从epoll中移除fd,这个fd必须健康合法,所以先移除后关闭epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);// 关闭fd::close(fd);}}void HandlerEvent(int n){for (int i = 0; i < n; i++){int fd = revs[i].data.fd;uint32_t revents = revs[i].events;LOG(INFO, "%d 有事件就绪,事件是%s\n", EventsToString(revents).c_str());if (revents & EPOLLIN){// 处理连接套接字if (fd == _listensock->Sockfd())Accepter();// 处理普通套接字elseHandlerIO(fd);}}}void Loop(){int timeout = 1000;while (1){int n = ::epoll_wait(_epfd, revs, num, timeout);switch (n){case 0:LOG(INFO, "epoll time out\n");break;case -1:LOG(ERROR, "epoll error\n");break;default:LOG(INFO, "haved event happend, n = %d\n", n);HandlerEvent(n);break;}}}~EpollServer(){if (_epfd >= 0)::close(_epfd);_listensock->Close();}private:uint16_t _port;unique_ptr<Socket> _listensock;int _epfd;// 定义epoll缓冲区struct epoll_event revs[num];
};

(5)epoll优点

接口方便

数据轻量级拷贝,只在合适的时间调用EPOLL_CTL_ADD将fd拷贝进入内核。

事件回调机制,避免使用遍历,就绪文件放入就绪队列,事件是O(1)

无数量限制fd

(6)epoll两种工作模式

a、LT水平触发

只要底层有数据,epoll就一直通知。

fd可以阻塞也可以非阻塞。

b、ET边缘触发

只有底层数据量变化epoll才通知。

逻辑链:ET模式只通知一次,本轮没读完不会通知 -> 一定要把数据全部读完 -> 循环读才能把数据读干净 -> 遇到阻塞问题? -> 把fd设非阻塞

c、ET vs LT

ET只通知一次,通知效率高。

ET每次都把数据读完,意味着留给对方接收窗口更大,IO效率更高。

所以要效率用ET,其余ET,LT都行

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

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

相关文章

CORDIC算法笔记整理

CORDIC算法有两种模式&#xff0c;分别为旋转模式和向量模式。而在数字硬件实现混频处理时&#xff0c;CORDIC算法是比较好的方法&#xff0c;使用的是CORDIC的旋转模式&#xff0c;只需通过移位操作和加法就可以实现频谱搬移的乘法操作。 1 CORDIC算法理解 1.1 单次旋转 对…

SpringCloud学习记录|day1

学习材料 2024最新SpringCloud微服务开发与实战&#xff0c;java黑马商城项目微服务实战开发&#xff08;涵盖MybatisPlus、Docker、MQ、ES、Redis高级等&#xff09; 学redis讲到微服务就停了&#xff0c;nginx也是。 所以嘛&#xff0c;我终于来到微服务了。 复习MyBatisP…

CMU 10423 Generative AI:lec14(Vision Language Model:CLIP、VQ-VAE)

文章目录 1 概述2 CLIP (Used in GPT-V)3 VQ-VAE (Used in Gemini)**VQ-VAE 详细笔记****VQ-VAE 的模块组成与数据流** **1. 输入数据****2. 编码器&#xff08;Encoder&#xff09;****2.1 编码器的作用****2.2 数据流与维度变化****2.3 编码器输出** **3. 量化器&#xff08;…

IP 数据包分包组包

为什么要分包 由于数据链路层MTU的限制,对于较⼤的IP数据包要进⾏分包. 什么是MTU MTU相当于发快递时对包裹尺⼨的限制.这个限制是不同的数据链路对应的物理层,产⽣的限制. • 以太⽹帧中的数据⻓度规定最⼩46字节,最⼤1500字节,ARP数据包的⻓度不够46字节,要在后⾯补填 充…

云栖实录 | 开源大数据全面升级:Native 核心引擎、Serverless 化、湖仓架构引领云上大数据发展

本文根据2024云栖大会实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a; 王 峰 | 阿里云智能集团研究员、开源大数据平台负责人 李 钰&#xff5c;阿里云智能集团资深技术专家 范 振&#xff5c;阿里云智能集团高级技术专家 李劲松&#xff5c;阿里云…

MongoDB聚合操作及索引底层原理

目录 链接:https://note.youdao.com/ynoteshare/index.html?id=50fdb657a9b06950fa255a82555b44a6&type=note&_time=1727951783296 本节课的内容: 聚合操作: 聚合管道操作: ​编辑 $match 进行文档筛选 ​编辑 将筛选和投影结合使用: ​编辑 多条件匹配: …

【AI】AIOT简介

随着技术的快速发展&#xff0c;人工智能AI和物联网IoT已经成为当今最热门的技术领域。AIOT是人工智能和物联网的结合&#xff0c;使物联网设备更加智能化&#xff0c;能够进行自主决策和学习的技术。 通过物联网产生、收集来自不同维度的、海量的数据存储于云端、边缘端&#…

数据治理006-数据标准的管理

元数据的分类和标准有哪些&#xff1f; 一、元数据的分类 元数据可以根据其描述的对象和属性不同&#xff0c;被分为不同的类型。以下是几种常见的元数据分类方法&#xff1a; 基于数据的类型&#xff1a;根据数据的类型&#xff0c;元数据可以被分为结构化元数据、非结构化元…

SQL连接Python

对于运营部门的Yoyo来说&#xff0c;她想要知道夜曲优选的订单都来自哪些省份&#xff0c;每个省份的总订单数以及总订单金额分别是多少。 这时小鹿就会通过SQL对连接的数据库进行查询&#xff0c;再将结果传递给Python处理&#xff0c;并帮助Yoyo生成可视化图表。 我们先来快…

拆解维修飞科剃须刀

原因 用了好几年的剃须刀&#xff0c;经过一次更换电池。后来上面的盖帽松动&#xff0c;无法合盖&#xff0c;经过把弹片矫正后修复。最近一次”大力出奇迹“的操作直接断送了这个老伤员最后的可能性。最终只能花了将近十块大洋买了一套盖着和中间座。简单更换了一下。 记录…

目前最好用的爬虫软件是那个?

作为一名数据工程师&#xff0c;三天两头要采集数据&#xff0c;用过十几种爬虫软件&#xff0c;也用过Python爬虫库&#xff0c;还是建议新手使用现成的软件比较方便。 这里推荐3款不错的自动化爬虫工具&#xff0c;八爪鱼、亮数据、Web Scraper 1. 八爪鱼爬虫 八爪鱼爬虫是一…

Linux:深入理解冯诺依曼结构与操作系统

目录 1. 冯诺依曼体系结构 1.1 结构分析 1.2 存储结构分布图 2. 操作系统 2.1 概念 2.2 如何管理 2.3 什么是系统调用和库函数 1. 冯诺依曼体系结构 1.1 结构分析 不管是何种计算机&#xff0c;如个人笔记本电脑&#xff0c;服务器&#xff0c;都是遵循冯诺依曼结构。…

可视化图表与源代码显示配置项及页面的动态调整功能分析

可视化图表与源代码显示配置项及页面的动态调整功能分析 文章目录 可视化图表与源代码显示配置项及页面的动态调整功能分析1.分析图表源代码2.分析源代码显示功能**完整代码参考&#xff1a;** 3.分析源代码显示及动态调整**完整代码参考&#xff1a;** 4.分析代码编辑器及运行…

华为云LTS日志上报至观测云最佳实践

华为云LTS简介 华为云云日志服务&#xff08;Log Tank Service&#xff0c;简称 LTS&#xff09;&#xff0c;用于收集来自主机和云服务的日志数据&#xff0c;通过海量日志数据的分析与处理&#xff0c;可以将云服务和应用程序的可用性和性能最大化&#xff0c;为您提供实时、…

基于SSM的爱心慈善公益网站的设计与实现

文未可获取一份本项目的java源码和数据库参考。 选题意义 随着经济的不断进步&#xff0c;发展各种进行公益事业的渠道不断的出现&#xff0c;作为一个礼仪之邦&#xff0c;中华民族一直秉承先人的团结与友善精神&#xff0c;对社会和他人给予帮助关怀。但中国的公益事业相对…

【AIGC】2022-CVPR-利用潜在扩散模型进行高分辨率图像合成

2022-CVPR-High-Resolution Image Synthesis with Latent Diffusion Models 利用潜在扩散模型进行高分辨率图像合成摘要1. 引言2. 相关工作3. 方法3.1. 感知图像压缩3.2. 潜在扩散模型3.3. 调节机制 4. 实验4.1. 关于感知压缩权衡4.2. 利用潜在扩散生成图像4.3. 条件潜在扩散4.…

防sql注入的网站登录系统设计与实现

课程名称 网络安全 大作业名称 防sql注入的网站登录系统设计与实现 姓名 学号 班级 大 作 业 要 求 结合mysql数据库设计一个web登录页面密码需密文存放&#xff08;可以采用hash方式&#xff0c;建议用sha1或md5加盐&#xff09;采用服务器端的验证码&#…

基于Hive和Hadoop的招聘分析系统

本项目是一个基于大数据技术的招聘分析系统&#xff0c;旨在为用户提供全面的招聘信息和深入的职位市场分析。系统采用 Hadoop 平台进行大规模数据存储和处理&#xff0c;利用 MapReduce 进行数据分析和处理&#xff0c;通过 Sqoop 实现数据的导入导出&#xff0c;以 Spark 为核…

英集芯IP5911:集成锂电池充电管理和检测唤醒功能的低功耗8位MCU芯片

英集芯IP5911是一款集成锂电池充电管理、咪头检测唤醒、负载电阻插拔和阻值检测等功能的8bit MCU芯片。其封装采用QFN16&#xff0c;应用时仅需极少的外围器件&#xff0c;就能够有效减小整体方案的尺寸&#xff0c;降低BOM成本&#xff0c;为小型电子设备提供高集成度的解决方…

【常读常悟】《大数据之路-阿里巴巴大数据实践》一书读书摘要

【常读常悟】《大数据之路-阿里巴巴大数据实践》一书读书摘要 1、背景2、目录结构3、数据加工链路4、章节摘要4.1 第2章 日志采集4.1.1 日志采集方案4.1.2 采集指标 4.2 第3章 数据同步4.2.1 数据的特点4.2.2 数据同步的三种方式4.2.3 数据同步的最佳实践 4.3 第4章 离线数据开…