当前位置: 首页 > news >正文

Linux之高级IO

目录

  • IO基本概念
  • 五种IO模型
    • 钓鱼人例子
    • 五种IO模型
    • 高级IO重要概念
    • 同步通信 VS 异步通信
    • 阻塞 VS 非阻塞
    • 其他高级IO
    • 阻塞IO
    • 非阻塞IO

IO基本概念

I/O(input/output)也就是输入和输出,在著名的冯诺依曼体系结构当中,将数据从输入设备拷贝到内存就叫做输入,将数据从内存拷贝到输出设备就叫做输出。

  • 对文件进行的读写操作本质就是一种IO,文件IO对应的外设就是磁盘。
  • 对网络进行的读写操作本质也是一种IO,网络IO对应的外设就是网卡。

IO存在最主要的问题就是效率问题,IO的效率极为低下的,我们以读取数据为例:

  • 当我们read/recv的时候,如果底层缓冲区中没有数据,read/recv就会阻塞等待;
  • 当我们read/recv的时候,如果底层缓冲区中有数据,read/recv就会进行拷贝,在学习TCP的时候我们知道read/recv等一系列接口本质就是拷贝函数。

由此我们就可以知道IO的本质就是等待 + 数据拷贝,只要缓冲区中没有数据,read/recv就会一直阻塞等待,直到缓冲区中出现数据,然后进行拷贝,所以说read/recv就会花费大量时间在等这一操作上面,这就是一种低效的IO模式。

我们如果想要解决这个问题,就需要让等的比重降低,这样,IO的效率就提高了,接下来我们以钓鱼人的例子来理解一下IO模型。

五种IO模型

钓鱼人例子

IO的过程其实跟钓鱼是非常相似的,IO中等的过程其实就相当于钓鱼等待鱼上钩的过程,而拷贝到过程就相当于把鱼从水里装进桶里的过程。

我们来看下面这五个人的钓鱼方式:

  • 张三:1根鱼竿,将鱼钩扔进水里以后,就一直盯着浮标一动不动,不理会外界的任何动静,直到鱼上钩;
  • 李四:1根鱼竿,将鱼钩扔进水里以后,可以干其他的事情,定期观察浮标的动静,如果鱼上钩就将鱼钓上来,没有就继续干其他事情;
  • 王五:1根鱼竿,但是在鱼竿上绑了一个铃铛,将鱼钩扔进水里以后,可以干其他的事情,铃铛一响就知道鱼上钩了,将鱼钓上来;
  • 赵六:100根鱼竿,将100根鱼竿都放置好,然后定期观察着100根鱼竿的状态,如果某个鱼竿有鱼上钩就将鱼钓上来;
  • 田七:田七是一个领导,带了一个司机,此时田七也想钓鱼,但是他要回公司开会,所以他拿来一根鱼竿,让自己的司机去钓鱼,让司机把桶装满了给他打电话来接他。

张三,李四和王五钓鱼的效率一样吗?

张三,李四和王五钓鱼的效率钓鱼的效率本质上是一样的,因为他们都是拿着一根鱼竿,在等待鱼上钩,鱼咬钩的概率是一样的。

他们只不过是等待鱼上钩的方式不一样,张三是死等,李四是定期检查浮标,王五则是通过铃铛的提示来判断鱼是否上钩。

谁的效率更高?

显而易见,赵六的效率是最高的,因为赵六有100根鱼竿,上鱼的概率是最大的,单位时间内,赵六鱼上钩的效率远远大于张三,李四和王五。

因为赵六减少了等待的概率发生,增加了拷贝的时间,所以效率是最高的。

如何看待田七钓鱼方式?

田七是将钓鱼这件事交给自己的司机去做了,自己就可以去干其他事情了,他并不关心司机是怎么钓鱼的,司机可以采用张三,李四,王五和赵六中的任意一种方式,田七只关心最后将桶装满了没。

田七并没有参与钓鱼的过程,他将钓鱼的任务安排给了司机,在司机钓鱼期间他可以做任何事情,如果将钓鱼看作是一种IO的话,那田七的这种钓鱼方式就叫做异步IO。

而对于张三、李四、王五、赵六来说,他们都需要自己等鱼上钩,当鱼上钩后又需要自己把鱼从河里钓上来,对应到IO当中就是需要自己进行数据的拷贝,因此他们四个人的钓鱼方式都叫做同步IO。

五种IO模型

这五个人的钓鱼方式对应了五种IO模型:

  • 张三这种死等方式叫做阻塞IO;
  • 李四这种定时检测的方式叫做非阻塞IO;
  • 王五这种通过设置铃铛得知事件是否就绪的方式就是信号驱动IO;
  • 王五这种一次等待多个鱼竿上有鱼的钓鱼方式就是IO多路转接;
  • 田七这种让别人帮自己钓鱼的钓鱼方式就是异步IO。

阻塞IO

阻塞IO就是在内核将数据准备好之前,系统调用会一直等待。

图示如下:

在这里插入图片描述

所有的套接字,默认的都是阻塞方式;

  • recvform读取数据时,由于底层的某些数据还没有准备就绪,此时就需要等待数据就绪,当数据就绪后就会将数据从内核拷贝到应用空间,最终 recvform函数返回成功;
  • recvform函数在等待过程中,本质上还是操作系统将该进程或者线程设置为某种非R状态,将其放入等待队列之中,而用户所看见的就是进程或者是线程阻塞住了,当数据就绪后操作系统就将等待的进程或线程唤醒,进而将数据从内核拷贝到应用空间;

非阻塞IO

非阻塞IO就是,如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回EWOULDBLOCK错误码。

图示如下:

在这里插入图片描述
非阻塞IO往往需要程序员以循环的方式反复尝试读写文件描述符,这个过程称为轮询,这对CPU来说是较大的浪费,一般只有特定场景下才使用。

  • 调用recvform函数时,如果底层数据没有准备好,此时就不会等待数据就绪,而是直接返回EWOULDBLOCK错误码,如果一直没有数据就绪,就会一直返回EWOULDBLOCK错误码,直到底层数据就绪,将数据拷贝到应用程序;
  • 每次recvform函数读取数据是,就算底层数据没有成功,依然会立马返回,在用户看来进程或线程就没有被阻塞住,我们就称之为非阻塞IO;

阻塞IO与非阻塞IO的最大区别就在于阻塞IO是操作系统识别到数据就绪后唤醒进程或线程,而非阻塞IO是用户一直进行检测,直到数据准备就绪。

信号驱动IO

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

图示如下:

在这里插入图片描述
当底层数据就绪的时候会向当前进程或线程递交SIGIO信号,因此可以通过signal或sigaction函数将SIGIO的信号处理程序自定义为需要进行的IO操作,当底层数据就绪时就会自动执行对应的IO操作。

  • 调用recvform函数从套接字上读取数据时,可以将该操作定义为SIGIO的信号处理程序,当底层数据就绪时,操作系统就会递交SIGIO信号,此时就会自动执行我们定义的信号处理程序,进程将数据从内核拷贝到用户空间;
  • 信号的产生是异步的,但信号驱动IO是同步IO的一种。信号在任何时刻都可能产生,但信号驱动IO是同步IO的一种,因为当底层数据就绪时,当前进程或线程需要停下正在做的事情,转而进行数据的拷贝操作,因此当前进程或线程仍然需要参与IO过程。

IO多路转接

IO多路转接也叫做IO多路复用,能够同时等待多个文件描述符的就绪状态。

在这里插入图片描述

  • IO的过程实际上是“等 + 拷贝的过程”, 调用recvform函数之后,数据未就绪就等,数据就绪了以后就进行数据的拷贝,但是尽管recvform可以实现“等这一操作”,但是一次只能等待一个文件描述符,效率太低了;
  • 所以系统为我们提供了select/epoll/poll三组接口,这些接口的核心工作就是“等”,我们可以将所有“等”的工作都交给这些多路转接接口;
  • 因为这些多路转接接口是一次“等”多个文件描述符的,因此能够将“等”的时间进行重叠,当数据就绪后再调用对应的recvfrom等函数进行数据的拷贝,此时这些函数就能够直接进行拷贝,而不需要进行“等”操作了。

异步IO

异步IO就是由内核在数据拷贝完成时,通知应用程序。

图示如下:

在这里插入图片描述

进行异步IO需要调用一些异步IO的接口,异步IO接口调用后会立马返回,因为异步IO不需要你进行“等”和“拷贝”的操作,这两个动作都由操作系统来完成,你要做的只是发起IO,当IO完成后操作系统会通知应用程序,因此进行异步IO的进程或线程并不参与IO的所有细节。

高级IO重要概念

同步通信 VS 异步通信

同步和异步关注的是消息通信机制。

  • 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回,但是一旦调用返回,就得到返回值了;换句话说,就是由调用者主动等待这个调用的结果。
  • 异步则是相反,调用在发出之后,这个调用就直接返回了,所有没有返回结果;换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果;而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。

为什么非阻塞IO在没有得到结果之前就返回了?

  • IO分为“等”和"拷贝”两步,当数据没有准备就绪的时候,recvform调用进行非阻塞IO时,就会直接返回,但是此时返回的并不是一个完整的IO过程,而是一个错误的返回;
  • 因此该进程或线程后续还需要继续调用recvfrom,轮询检测数据是否就绪,当数据就绪后最后再把数据从内核拷贝到用户空间,这才是一次完整的IO过程。

因此,在进行非阻塞IO时,在没有得到结果之前,虽然这个调用会返回,但后续还需要继续进行轮询检测,因此可以理解成调用还没有返回,而只有当某次轮询检测到数据就绪,并且完成数据拷贝后才认为该调用返回了。

同步通信 VS 同步与互斥

在多进程与多线程里面有同步与互斥的概念,IO中也存在同步的概念,但是这两个同步是完全不相干的。

  • 多进程与多线程下同步是指,在保证数据安全的前提下,让进程或线程按照某种特定的方式访问临界资源,从而有效的避免了饥饿问题,讨论的是线程/进程间的工作关系;
  • 而同步IO指的是进程/线程与操作系统之间的关系,谈论的是进程/线程是否需要主动参与IO过程。

阻塞 VS 非阻塞

阻塞和非阻塞关注的是程序在等待调用结果(消息、返回值)时的状态。

  • 阻塞调用是指调用结果返回之前,当前线程会被挂起,调用线程只有在得到结果之后才会返回。
  • 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

其他高级IO

非阻塞IO,记录锁,系统V流机制,I/O多路转接(也叫I/O多路复用),readv和writev函数以及存储映射IO(mmap),这些统称为高级IO。

阻塞IO

我们可以用read函数从标准输入当中读取数据为例:

#include <iostream>
#include <unistd.h>int main()
{char buffer[1024];while (true){ssize_t s = read(0, buffer, sizeof(buffer) - 1);if (s > 0){buffer[s] = 0;std::cout << "echo# " << buffer << std::endl;}else{std::cout << "read error" << std::endl;}}return 0;
}

程序运行以后,我们会发现,如果我们不进行数据的输入操作,程序就会一直阻塞住,根本原因就是底层数据没有就绪,read函数在阻塞式等待。

在这里插入图片描述
当我们输入数据以后,此时read函数就会检测到底层的数据已经就绪了,就会将缓冲区中的数据拷贝到我们的buffer数组中,并且将读取到的数据输出到显示器上面,最后我们就看到了我们输入的字符串。

在这里插入图片描述

非阻塞IO

打开文件时默认都是以阻塞的方式打开的,如果要以非阻塞的方式打开某个文件,需要在使用open函数打开文件时携带O_NONBLOCKO_NDELAY选项,此时就能够以非阻塞的方式打开文件。

在这里插入图片描述
我们一般用统一的方式来进行非阻塞设置,就是fcntl函数。

fcntl函数

fcntl函数的原型如下:

int fcntl(int fd, int cmd, ... /* arg */ );

参数说明:

  • fd:已经打开的文件描述符。
  • cmd:需要进行的操作。
  • :可变参数,传入的cmd值不同,后面追加的参数也不同。

fcntl函数常用的5种功能与其对应的cmd取值如下:

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

返回值说明:

  • 如果函数调用成功,则返回值取决于具体进行的操作。
  • 如果函数调用失败,则返回-1,同时错误码会被设置。

实现函数SetNoBlock

基于fcntl, 我们实现一个SetNoBlock函数,将文件描述符设置为非阻塞。

bool SetNoBlock(int fd)
{// 在底层获取fd对应文件描述符的标志位int fl = fcntl(fd, F_GETFL);if (fl < 0)return false;// 设置非阻塞IOfcntl(fd, F_SETFL, fl | O_NONBLOCK);return true;
}

此时我们在以非阻塞轮询方式读取标准输入。

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>bool SetNoBlock(int fd)
{// 在底层获取fd对应文件描述符的标志位int fl = fcntl(fd, F_GETFL);if (fl < 0)return false;// 设置非阻塞IOfcntl(fd, F_SETFL, fl | O_NONBLOCK);return true;
}
int main()
{SetNoBlock(0);char buffer[1024];while (true){sleep(1);ssize_t s = read(0, buffer, sizeof(buffer) - 1);if (s > 0){buffer[s] = 0;std::cout << "echo# " << buffer << std::endl;}else{std::cout << "read error "<< "errno: " << errno << "errstring: " << strerror(errno) << std::endl;if (errno == EWOULDBLOCK || errno == EAGAIN){std::cout << "当前0号fd数据未就绪,请再试一次" << std::endl;continue;}else if (errno == EINTR){std::cout << "当前IO信号可能被中断,请再试一次" << std::endl;continue;}}}return 0;
}

需要注意的是,调用read函数以后,如果底层数据没有就绪,就会立马返回一个错误信息,但是此时我们是需要对返回的的错误信息进行甄别的,我们需要知道是真的出错了还是只是底层数据没有就绪。如果错误码的值是EAGAINEWOULDBLOCK,说明本次调用read函数出错是因为底层数据还没有就绪,因此后续还应该继续调用read函数进行轮询检测数据是否就绪,当数据继续时再进行数据的读取。

此外,调用read函数在读取到数据之前可能会被其他信号中断,此时read函数也会以出错的形式返回,此时的错误码会被设置为EINTR,此时应该重新执行read函数进行数据的读取。

程序运行以后,底层数据如果没有就绪,此时read函数就会轮询进行检测:

在这里插入图片描述
一旦我们进行了输入操作,此时read函数就会在轮询检测时检测到,紧接着立马将数据读取到从内核拷贝到我们传入的buffer数组当中,并且将读取到的数据输出到显示器上面,然后继续进行轮询检测。
在这里插入图片描述

相关文章:

Linux之高级IO

目录 IO基本概念五种IO模型钓鱼人例子五种IO模型高级IO重要概念同步通信 VS 异步通信阻塞 VS 非阻塞其他高级IO阻塞IO非阻塞IO IO基本概念 I/O&#xff08;input/output&#xff09;也就是输入和输出&#xff0c;在著名的冯诺依曼体系结构当中&#xff0c;将数据从输入设备拷贝…...

进程和线程的关系

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;JavaEE &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 进程&线程 1. 什么是进程PCB 2. 什么是…...

YOLOv5全网独家改进:NanoDet算法动态标签分配策略(附原创改进代码),公开数据集mAP有效涨点,来打造新颖YOLOv5检测器

💡本篇内容:YOLOv5全网独家改进:NanoDet算法动态标签分配策略(附原创改进代码),公开数据集mAP有效涨点,来打造新颖YOLOv5检测器 💡🚀🚀🚀本博客 YOLOv5+ 改进NanoDet模型的动态标签分配策略源代码改进 💡一篇博客集成多种创新点改进:NanoDet 💡:重点:更…...

原生DOM事件、react16、17和Vue合成事件

目录 原生DOM事件 注册/绑定事件 DOM事件级别 DOM0&#xff1a;onclick传统注册&#xff1a; 唯一&#xff08;同元素的(不)同事件会覆盖&#xff09; 没有捕获和冒泡的&#xff0c;只有简单的事件绑定 DOM2&#xff1a;addEventListener监听注册&#xff1a;可添加多个…...

基于HTML+CSS+JavaScript的登录注册界面设计

一、界面效果: 二、HTML代码: 登录注册html: 登录成功html: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <h1>登录成功!</h1> </body> <…...

BUUCTF [MRCTF2020]Ez_bypass 1

题目环境&#xff1a;F12查看源代码 I put something in F12 for you include flag.php; $flagMRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}; if(isset($_GET[gg])&&isset($_GET[id])) { $id$_GET[id]; $gg$_GET[gg]; if (md5($id) md5($gg) && $id ! $gg) { …...

基于Apache部署虚拟主机网站

文章目录 Apache释义Apache配置关闭防火墙和selinux 更改默认页内容更改默认页存放位置个人用户主页功能基于口令登录网站虚拟主机功能基于ip地址相同ip不同域名相同ip不同端口 学习本章完成目标 1.httpd服务程序的基本部署。 2.个人用户主页功能和口令加密认证方式的实现。 3.…...

大数据平台/大数据技术与原理-实验报告--部署全分布模式HBase集群和实战HBase

实验名称 部署全分布模式HBase集群和实战HBase 实验性质 &#xff08;必修、选修&#xff09; 必修 实验类型&#xff08;验证、设计、创新、综合&#xff09; 综合 实验课时 2 实验日期 2023.11.07-2023.11.10 实验仪器设备以及实验软硬件要求 专业实验室&#xff…...

手写字符识别神经网络项目总结

1.数据集 手写字符数据集 DIGITS&#xff0c;该数据集的全称为 Pen-Based Recognition of Handwritten Digits Data Set&#xff0c;来源于 UCI 开放数据集网站。 2.加载数据集 import numpy as np from sklearn import datasets digits datasets.load_digits() 3.分割数…...

八、Lua数组和迭代器

一、Lua数组 数组&#xff0c;就是相同数据类型的元素按一定顺序排列的集合&#xff0c;可以是一维数组和多维数组。 在 Lua 中&#xff0c;数组不是一种特定的数据类型&#xff0c;而是一种用来存储一组值的数据结构。 实际上&#xff0c;Lua 中并没有专门的数组类型&#xf…...

平凯星辰 TiDB 获评 “2023 中国金融科技守正创新扬帆计划” 十佳优秀实践奖

11 月 10 日&#xff0c;2023 金融街论坛年会同期举办了“第五届成方金融科技论坛——金融科技守正创新论坛”&#xff0c;北京金融产业联盟发布了“扬帆计划——分布式数据库金融应用研究与实践优秀成果”&#xff0c; 平凯星辰提报的实践报告——“国产 HTAP 数据库在金融规模…...

运算符展开、函数,对象,数组,字符串变化 集合

... 展开运算符 用于函数实参或者赋值号右边 console.log(...[1, 2, 3]) // 1,2,3console.log(Math.max(...[1, 2, 3]))//3 console.log(Math.max.apply(null, [1, 2, 3]))//3const o { a: 1, b: 2 }const obj { ...o, c: 3 }console.log(obj)//Object ... 剩余运算符 用于…...

NI自动化测试系统用电必备攻略,电源规划大揭秘

就像使用电脑之前需接通电源一样&#xff0c;自动化测试系统的电源选择也是首当其冲的问题&#xff0c;只不是这个问题更复杂。 比如&#xff0c;应考虑地理位置因素&#xff0c;因为不同国家或地区的公共电网所提供的线路功率有所不同。在电源布局和设备选型方面&#xff0c;有…...

ky10 server arm 在线编译安装openssl3.1.4

在线编译脚本 #!/bin/shOPENSSLVER3.1.4OPENSSL_Vopenssl versionecho "当前OpenSSL 版本 ${OPENSSL_V}" #------------------------------------------------ #wget https://www.openssl.org/source/openssl-3.1.4.tar.gzecho "安装OpenSSL${OPENSSLVER}...&q…...

外网IP和内网IP的区别

首先得先知道什么是ip地址&#xff0c;它就是唯一标识连接网络的设备的&#xff0c;即IP地址充当了设备在网络中的“住址”&#xff0c;使得设备能够相互通信和交换数据。 我们常听开发人员说外网内网&#xff0c;那么它们有什么区别呢&#xff1f; 外网可以理解为互联网&…...

Jquery动画特效

1&#xff0c;Jquery提供的特效方法 2&#xff0c;实例代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…...

Tableau连接到mysql数据库,配置驱动

Tableau想要连接mysql数据库进行数据的可视化&#xff0c;但是没有ODBC驱动&#xff0c;看了几篇文章写的&#xff0c;不是很清楚&#xff0c;顺便写下自己的思路。 1、下载mysql对应的ODBC驱动 首先要知道自己mysql的版本&#xff0c;然后下载对应的ODBC驱动。 MySQL :: Dow…...

HuggingFace学习笔记--AutoModel的使用

1--AutoModel的使用 官方文档 AutoModel 用于加载模型&#xff1b; 1-1--简单Demo 测试代码&#xff1a; from transformers import AutoTokenizer, AutoModelif __name__ "__main__":checkpoint "distilbert-base-uncased-finetuned-sst-2-english"t…...

Kafka常见面试问题

1、Kafka分区设计及主副本如何同步 Apache Kafka是一种分布式流处理平台&#xff0c;它使用分布式复制协议来实现高可用性和容错性。在Kafka中&#xff0c;每个主题&#xff08;topic&#xff09;都有一个或多个分区&#xff08;partition&#xff09;&#xff0c;每个分区都有…...

学习知识回顾随笔(远程连接MySQL|远程访问Django|HTTP协议|Web框架)

文章目录 如何远程连接MySQL数据库1.创建用户来运行&#xff0c;此用户从任何主机连接到mysql数据库2.使用IP地址来访问MySQL数据库 如何远程访问Django项目Web应用什么是Web应用应用程序的两种模式Web应用程序的优缺点 HTTP协议&#xff08;超文本传输协议&#xff09;简介HTT…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...