浅析linux异步io框架 io_uring
前言
Linux内核5.1支持了新的异步IO框架iouring,由Block IO大神也即Fio作者Jens Axboe开发,意在提供一套公用的网络和磁盘异步IO,不过io_uring目前在磁盘方面要比网络方面更加成熟。
目录
-
背景简介
-
io_uring
-
系统API
-
liburing
-
高级特性
-
编程示例
-
性能对比
-
模式对比
-
线上应用
背景简介
熟悉Linux系统编程的同学都清楚,Linux并没有提供完善的异步IO(网络IO、磁盘IO)机制。
在网络编程中,我们通常使用epoll IO多路复用来处理网络IO,然而epoll也并不是异步网络IO,仅仅是内核提供了IO复用机制,epoll回调通知的是数据可以读取或者写入了,具体的读写操作仍然需要用户去做,而不是内核代替完成。
在存储IO栈中,做存储的同学大都使用过libaio,然而那是一个巨难用啊Linux AIO这个奇葩。首先只能在DIO下使用,用不了pagecache;其次用户的数据地址空间起始地址和大小必须页大小对齐;然后在submit_io时仍然可能因为文件系统、pagecache、sync发生阻塞,除此之外,我们在使用libaio的时候会设置io_depth的大小,还可能因为内核的/sys/block/sda/queue/nr_requests(128)设置的过小而发生阻塞;而且libaio提供的sync命令关键还不起作用,想要sync数据还得依赖fsync/fdatasync,真的是心塞塞,libaio想说爱你不容易啊。
所以Linux迫切需要一个完善的异步机制。同时在Linux平台上跑的大多数程序都是专用程序,并不需要内核的大多数功能,而且这几年也流行kernel bypass,intel也发起的用户态IO DPDK、SPDK。但是这些用户态IO API不统一,使用成本过高,所以内核便推出了io_uring来统一网络和磁盘的异步IO,提供一套统一完善的异步API,也支持异步、轮询、无锁、zero copy。真的是姗姗来迟啊,不过也算是在高性能IO方面也算是是扳回了一城。
io_uring
io_uring的设计目标是提供一个统一、易用、可扩展、功能丰富、高效的网络和磁盘系统接口。其高性能依赖于以下几个方面:
-
用户态和内核态共享提交队列(submission queue)和完成队列(completion queue)。
-
用户态支持Polling模式,不依赖硬件的中断,通过调用IORING_ENTER_GETEVENTS不断轮询收割完成事件。
-
内核态支持Polling模式,IO 提交和收割可以 offload 给 Kernel,且提交和完成不需要经过系统调用(system call)。
-
在DirectIO下可以提前注册用户态内存地址,减小地址映射的开销。
系统API
io_uring提供了3个系统调用API,虽然只有3个,但是直接使用起来还是蛮复杂的。
-
io_uring_setup
int io_uring_setup(unsigned entries, struct io_uring_params *params);
entries:queue depth,表示队列深度。
io_uring_params:初始化时候的参数。
在io_uring_setup返回的时候就已经初始化好了 SQ 和 CQ,此外,还有内核还提供了一个 Submission Queue Entries(SQEs)数组。
添加图片注释,不超过 140 字(可选)
之所以额外采用了一个数组保存 SQEs,是为了方便通过 RingBuffer 提交内存上不连续的请求。SQ 和 CQ 中每个节点保存的都是 SQEs 数组的偏移量,而不是实际的请求,实际的请求只保存在 SQEs 数组中。这样在提交请求时,就可以批量提交一组 SQEs 上不连续的请求。 但由于 SQ,CQ,SQEs 是在内核中分配的,所以用户态程序并不能直接访问。io_setup 的返回值是一个 fd,应用程序使用这个 fd 进行 mmap,和 kernel 共享一块内存。 这块内存共分为三个区域,分别是 SQ,CQ,SQEs。kernel 返回的 io_sqring_offset 和 io_cqring_offset 分别描述了 SQ 和 CQ 的指针在 mmap 中的 offset。而 SQEs 则直接对应了 mmap 中的 SQEs 区域。 mmap 的时候需要传入 MAP_POPULATE 参数,以防止内存被 page fault。
-
io_uring_enter
int io_uring_enter(unsigned int fd, u32 to_submit, u32 min_complete, u32 flags);
io_uring_enter即可以提交io,也可以来收割完成的IO,一般IO完成时内核会自动将SQE 的索引放入到CQ中,用户可以遍历CQ来处理完成的IO。
IO 提交的做法是找到一个空闲的 SQE,根据请求设置 SQE,并将这个 SQE 的索引放到 SQ 中。SQ 是一个典型的 RingBuffer,有 head,tail 两个成员,如果 head == tail,意味着队列为空。SQE 设置完成后,需要修改 SQ 的 tail,以表示向 RingBuffer 中插入一个请求。
io_uring_enter 被调用后会陷入到内核,内核将 SQ 中的请求提交给 Block 层。to_submit 表示一次提交多少个 IO。
如果 flags 设置了 IORING_ENTER_GETEVENTS,并且 min_complete > 0,那么这个系统调用会同时处理 IO 收割。这个系统调用会一直 block,直到 min_complete 个 IO 已经完成。
这个流程貌似和 libaio 没有什么区别,IO 提交的过程中依然会产生系统调用。
但 io_uring 的精髓在于,提供了 submission offload 模式,使得提交过程完全不需要进行系统调用。
如果在调用 io_uring_setup 时设置了 IORING_SETUP_SQPOLL 的 flag,内核会额外启动一个内核线程,我们称作 SQ 线程。这个内核线程可以运行在某个指定的 core 上(通过 sq_thread_cpu 配置)。这个内核线程会不停的 Poll SQ,除非在一段时间内没有 Poll 到任何请求(通过 sq_thread_idle 配置),才会被挂起。
当程序在用户态设置完 SQE,并通过修改 SQ 的 tail 完成一次插入时,如果此时 SQ 线程处于唤醒状态,那么可以立刻捕获到这次提交,这样就避免了用户程序调用 io_uring_enter 这个系统调用。如果 SQ 线程处于休眠状态,则需要通过调用 io_uring_enter,并使用 IORING_SQ_NEED_WAKEUP 参数,来唤醒 SQ 线程。用户态可以通过 sqring 的 flags 变量获取 SQ 线程的状态。
https://github.com/axboe/liburing/blob/master/src/queue.c#L22if (IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_NEED_WAKEUP) {*flags |= IORING_ENTER_SQ_WAKEUP;return true;
}
-
io_uring_register
主要包含IORING_REGISTER_FILES、IORING_REGISTER_BUFFERS,在高级特性章节会描述。
int io_uring_register(unsigned int fd, unsigned int opcode, void *arg, unsigned int nr_args)
相关视频推荐
程序性能上不去怎么办? 异步来解决你的问题
4个方面深度剖析 不得不了解的io_uring
准备好4台虚拟机,实现服务器的百万级并发
免费学习地址:c/c++ linux服务器开发/后台架构师
需要C/C++ Linux服务器架构师学习资料加qun579733396获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
liburing
我们知道io_uring虽然仅仅提供了3个系统API,但是想要用好还是有一定难度的,所提fio大神本人封装了一个Liburing,简化了io_uring的使用,通过使用liburing,我们很容易写出异步IO程序。
代码位置:github.com/axboe/liburi,在使用的时候目前仍然需要拉取代码,自己编译,估计之后将会融入内核,在用户程序中需要包含#include "liburing.h"。
列举一些比较常用的封装的API:github.com/axboe/liburi
// 非系统调用,初始化io_uring,entries:队列深度 queue depth
extern int io_uring_queue_init(unsigned entries, struct io_uring *ring, unsigned flags);// 非系统调用,清理io_uring
extern void io_uring_queue_exit(struct io_uring *ring);// 非系统调用,获取一个可用的 submit_queue_entry,用来提交IO
extern struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring);// 非系统调用,准备阶段,和libaio封装的io_prep_writev一样
static inline void io_uring_prep_writev(struct io_uring_sqe *sqe, int fd,const struct iovec *iovecs, unsigned nr_vecs, off_t offset)// 非系统调用,准备阶段,和libaio封装的io_prep_readv一样
static inline void io_uring_prep_readv(struct io_uring_sqe *sqe, int fd, const struct iovec *iovecs, unsigned nr_vecs, off_t offset)// 非系统调用,把准备阶段准备的data放进 submit_queue_entry
static inline void io_uring_sqe_set_data(struct io_uring_sqe *sqe, void *data)// 非系统调用,设置submit_queue_entry的flag
static inline void io_uring_sqe_set_flags(struct io_uring_sqe *sqe, unsigned flags)// 非系统调用,提交sq的entry,不会阻塞等到其完成,内核在其完成后会自动将sqe的偏移信息加入到cq,在提交时需要加锁
extern int io_uring_submit(struct io_uring *ring);// 非系统调用,提交sq的entry,阻塞等到其完成,在提交时需要加锁。
extern int io_uring_submit_and_wait(struct io_uring *ring, unsigned wait_nr);// 非系统调用 宏定义,会遍历cq从head到tail,来处理完成的IO
#define io_uring_for_each_cqe(ring, head, cqe)// 非系统调用 遍历时,可以获取cqe的data
static inline void *io_uring_cqe_get_data(const struct io_uring_cqe *cqe)// 非系统调用 遍历完成时,需要调整head往后移nr
static inline void io_uring_cq_advance(struct io_uring *ring, unsigned nr)
高级特性
io_uring里面提供了polling机制:IORING_SETUP_IOPOLL可以让内核采用 Polling 的模式收割 Block 层的请求;IORING_SETUP_SQPOLL可以让内核新起线程轮询提交sq的entry。
IORING_REGISTER_FILES
这个的用途是避免每次 IO 对文件做 fget/fput 操作,当批量 IO 的时候,这组原子操作可以避免掉。
IORING_REGISTER_BUFFERS
如果应用提交到内核的虚拟内存地址是固定的,那么可以提前完成虚拟地址到物理 pages 的映射,避免在 IO 路径上进行转换,从而优化性能。用法是,在 setup io_uring 之后,调用 io_uring_register,传递 IORING_REGISTER_BUFFERS 作为 opcode,参数是一个指向 iovec 的数组,表示这些地址需要 map 到内核。在做 IO 的时候,使用带 FIXED 版本的opcode(IORING_OP_READ_FIXED /IORING_OP_WRITE_FIXED)来操作 IO 即可。
内核在处理 IORING_REGISTER_BUFFERS 时,提前使用 get_user_pages 来获得 userspace 虚拟地址对应的物理 pages。在做 IO 的时候,如果提交的虚拟地址曾经被注册过,那么就免去了虚拟地址到 pages 的转换。
IORING_SETUP_IOPOLL
这个功能让内核采用 Polling 的模式收割 Block 层的请求。当没有使用 SQ 线程时,io_uring_enter 函数会主动的 Poll,以检查提交给 Block 层的请求是否已经完成,而不是挂起,并等待 Block 层完成后再被唤醒。使用 SQ 线程时也是同理。
编程示例
通过liburing使用起来还是比较方便的,不用操心内核的一些事情,简直爽歪歪啊。具体可参考ceph:github.com/ceph/ceph/bl
-
io_uring_queue_init 来初始化 io_uring。IORING_SETUP_IOPOLL / IORING_SETUP_SQPOLL。
-
io_uring_submit 来提交 IO,在这个函数里面会判断是否需要调用系统调用io_uring_enter。设置了IORING_SETUP_SQPOLL则不需要调用,没有设置则需要用户调用。
-
io_uring_for_each_cqe 来收割完成的IO,这是一个for循环宏定义,后面直接跟 {} 就可以。
性能对比
intel团队测试结果
可以看出来intel自己测试的结果表明延迟方面spdk比io_uring要低60%。使用了自己带的perf的测试工具测的。
fio作者测试结果
4k randread,3D Xpoint 盘:
io_uring vs libaio,在非 polling 模式下,io_uring 性能提升不到 10%,好像并没有什么了不起的地方。
然而 io_uring 提供了 polling 模式。在 polling 模式下,io_uring 和 SPDK 的性能非常接近,特别是高 QueueDepth 下,io_uring 有赶超的架势,同时完爆 libaio。
模式对比
项目 | io_uring | spdk |
---|---|---|
驱动程序 | 内核态驱动程序有锁 | 用户态驱动程序、无锁、轮询、线程绑定 |
run_to_completion | 非rtc模型,可能会有上下文切换? | rtc模型,单线程撸到底 |
内存管理 | mmu、4k | 2MB大页 |
提交任务有无锁 | 无锁 | 无锁 |
系统调用 | 可有可无 | 无系统调用 |
用户内核态切换 | 轻量级的 | 无内核切换 |
poll模型 | 可选 | polling |
线上应用
目前发现已经有几个项目在做尝试性的应用:rocksdb、ceph、spdk、第三方适配(nginx、redis、echo_server)
rocksdb
rocksdb官方实现了PosixRandomAccessFile::MultiRead()使用io_uring。
添加图片注释,不超过 140 字(可选)
除此之外,tikv扩展了一些实现:openinx.github.io/ppt/i
-
wal和sstbale的写入使用io_uring,但是测完之后性能提升不明显。
-
compaction file write的时间降低了一半。
-
可用io_uring优化的点:参考 Conclusion & Future work 章节。
spdk
SPDK与io_uring新异步IO机制,在其抽象的通用块层加入了io_uring的支持。
添加图片注释,不超过 140 字(可选)
ceph
ceph的io_uring主要使用在block_device,抽象出了统一的块设备,直接操作裸设备,对上层提供统一的读写方法。
bluefs仅仅需要提供append only的写入即可,不需要提供随机写,大大简化了bluefs的实现。
添加图片注释,不超过 140 字(可选)
第三方适配(nginx、redis、echo_server)
第三方io_uring适配(nginx、redis、echo_server)性能测试结果:
redis:
以下是 redis 在 event poll 和 io_uring 下的 qps 对比:
-
高负载情况下,io_uring 相比 event poll,吞吐提升 8%~11%。
-
开启 sqpoll 时,吞吐提升 24%~32%。这里读者可能会有个疑问,开启 sqpoll 额外使用了一个 CPU,性能为什么才提升 30% 左右?那是因为 redis 运行时同步读写就消耗了 70% 以上的 CPU,而 sq_thread 只能使用一个 CPU 的能力,把读写工作交给 sq_thread 之后,理论上 QPS 最多能提升 40% 左右(1/0.7 - 1 = 0.42),再加上 sq_thread 还需要处理中断以及本身的开销,因此只能有 30% 左右的提升。
nginx:
-
单 worker 场景,当连接数超过 500 时,QPS提升 20% 以上。
-
connection 固定 1000,worker 数目在 8 以下时,QPS 有 20% 左右的提升。随着 worker 数目增大,收益逐渐降低。
-
短连接场景,io uring 相对于 event poll 非但没有提升,甚至在某些场景下有 5%~10% 的性能下降。究其原因,除了 io uring 框架本身带来的开销以外,还可能跟 io uring 编程模式下请求批量下发带来的延迟有关。
相关文章:
浅析linux异步io框架 io_uring
前言 Linux内核5.1支持了新的异步IO框架iouring,由Block IO大神也即Fio作者Jens Axboe开发,意在提供一套公用的网络和磁盘异步IO,不过io_uring目前在磁盘方面要比网络方面更加成熟。 目录 背景简介 io_uring 系统API liburing 高级特性…...
访问者模式的一个使用案例——文档格式转换
访问者模式的一个使用案例——文档格式转换 假设我们在开发一个文档编辑器,它支持多种不同的文档元素(如段落、图片、表格等),现在我们需要添加一个功能——将文档导出为 HTML 或 Markdown 格式。 这就是一个典型的访问者模式的…...
【MySql】数据库的聚合查询
写在最前面的话 哈喽,宝子们,今天给大家带来的是MySql数据库的聚合查询。在前面CRUD章节我们学习了表达式查询,表达式查询是针对列和列之间进行运算的,那么如果想在行和行之间进行运算,那么就需要用到聚合查询。聚合查…...
Linux初探 - 概念上的理解和常见指令的使用
目录 Linux背景 Linux发展史 GNU 应用场景 发行版本 从概念上认识Linux 操作系统的概念 用户的概念 路径与目录 Linux下的文件 时间戳的概念 常规权限 特殊权限 Shell的概念 常用指令 ls tree stat clear pwd echo cd touch mkdir rmdir rm cp mv …...
苹果上架Guideline 4.3 - Design
最近上架苹果商店,审核提示 Guideline 4.3 - DesignWe noticed your app shares a similar binary, metadata, and/or concept as apps previously submitted by a terminated Apple Developer Program account.Submitting similar or repackaged apps is a form o…...
【数据分析入门】【淘宝电商API接入与电商数据分析】初识Web API(一)
今天开始我们将学习如何使用Web应用变成借口(API)自动请求网站到特定信息而不是整个网站,再对这些信息进行可视化。由于这样编写到程序始终使用最新到数据来生成可视化,因此即便数据瞬息万变,它呈现到信息也都是最新的。比如,我们…...
蓝桥杯官网练习题(李白打酒)
题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 话说大诗人李白,一生好饮。幸好他从不开车。 一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱: …...
聚类分析 | MATLAB实现基于SOM自组织特征映射聚类可视化
聚类分析 | MATLAB实现基于SOM自组织特征映射聚类可视化 目录 聚类分析 | MATLAB实现基于SOM自组织特征映射聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于自组织特征映射聚类算法(SOM)的数据聚类可视化 可直接运行 注释清晰 Matlab语言 1.多特征输入&…...
Spring AOP:面向切面编程在实际项目中的应用
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
python爬虫的反扒技术有哪些如何应对
Python爬虫常见的反扒技术主要有以下几种: IP封禁:有些网站会限制爬虫的IP访问频率,如果访问流量过大,可能会被封禁IP。可以通过使用代理IP或者轮换IP的方式规避此类反扒技术。 用户代理限制:有些网站会通过检测请求头中的用户代…...
网络原理,了解xml, json,protobuffer的特点
目录 外卖服务器场景带入 大佬们通用的规范格式 一、👦 外卖服务器场景 外面服务器沟通有很多模式——展示商家列表等等,只是其中一个,因此需要一个统一的规划了——不同应用程序,里面的自定义格式是不一样的,这样的…...
工具 | XShell的学习与使用
工具 | XShell的学习与使用 时间:2023年9月8日09:03:29 文章目录 工具 | XShell的学习与使用1.下载2.安装 1.下载 1.官网XSHELL - NetSarang Website 2.免费版下载:家庭/学校免费 - NetSarang Website (xshell.com) 3.https://cdn.netsarang.net/de06d10…...
基于微服务+Java+Spring Cloud +UniApp +MySql开发的智慧工地源码(物联网、人工智能、AI识别、危大工程)
智慧工地系统利用物联网、人工智能、云计算、大数据、移动互联网等新一代信息技术,通过工地中台、三维建模服务、视频AI分析服务等技术支撑,实现智慧工地高精度动态仿真,趋势分析、预测、模拟,建设智能化、标准化的智慧工地综合业…...
Kafka安装与使用
Kafka是一种高吞吐量的分布式发布订阅消息系统,因为其高吞吐量、分布式可扩展性等等强大功能使得在目前互联网系统中广泛使用。该篇博客入门了解一下Kafka的安装及使用。 Kafka概念 Kafk是分布式消息队列。Kafka对消息保存时根据Topic进行归类,发送消息…...
php出现SSL certificate problem: unable to get local issuer certificate的解决办法
当在本地使用curl或者一些其它封装好的http类库或组件(如php界 知名的 http客户端 Guzzle)需要访问https时,如果本地没有配置证书,会出现SSL certificate problem: unable to get local issuer certificate的报错信息。 解决办法一…...
Flask狼书笔记 | 07_留言板
文章目录 7 留言板7.1 使用包组织代码7.2 Web开发流程7.3 使用Bootstrap-Flask7.4 Flask-Moment本地化日期和时间7.5 使用Faker生成虚拟数据7.6 Flask_DebugToolbar调试程序7.7 Flask配置的两种组织形式小结 7 留言板 这是一个简单的程序,涉及到的大部分是之前所学…...
文件导入之Validation校验List对象数组
背景: 我们的接口是一个List对象,对象里面的数据基本都有一些基础数据校验的注解,我们怎么样才能校验这些基础规则呢? 我们在导入excel文件进行数据录入的时候,数据录入也有基础的校验规则,这个时候我们又…...
【Linux】文件系统
磁盘及文件系统 文件的增删查改 重新认识目录 目录是文件嘛? 是的。 目录有iNode嘛? 有 目录有内容嘛? 有 任何一个文件,一定在一个目录内部,所以一个目录的内容是什么? 需要数据块,目录的数据…...
1.5 空间中的平面与直线
空间中的平面和直线 知识点1 平面方程 1.平面的法向量与法式 定义1 若向量n 垂直与平面N,则称向量n为平面N的法向量。 设一平面通过一直点 M 0 ( x 0 , y 0 , z 0 ) M_0(x_0,y_0,z_0) M0(x0,y0,z0)求垂直于非零向量 n ⃗ \vec{n} n (A,B,C),求改平面N的…...
【深度学习】实验06 使用TensorFlow完成线性回归
文章目录 使用TensorFlow完成线性回归1. 导入TensorFlow库2. 构造数据集3. 定义基本模型4. 训练模型5. 线性回归图 附:系列文章 使用TensorFlow完成线性回归 TensorFlow是由Google开发的一个开源的机器学习框架。它可以让开发者更加轻松地构建和训练深度学习模型&a…...
2023国赛 C题论文 蔬菜类商品自动定价与补货策略
因为一些不可抗力,下面仅展示小部分论文,其余看文末 一、问题重述 在生鲜超市管理领域,涉及一系列复杂问题,包括供应链管理、定价策略以及市场需求分析等方面。以蔬菜类商品为案例,这些商品在生鲜商超中具有较短的保…...
使用 【jacoco】对基于 SpringBoot 和 Dubbo RPC 的项目生成测试覆盖率报告:实践+原理
基于 Dubbo RPC 的项目中有一个提供者项目backend、一个消费者项目gateway、以及注册中心nacos。本篇文章记录在windows本地对该框架的测试过程,以及介绍jacoco的基本原理 测试过程 官网下载安装包解压到本地,https://www.jacoco.org/jacoco/ 只需要用…...
Mac OS合集
MacOS 10.15os 提取码:u12a 如不能点击跳转请复制此链接到浏览器:https://pan.baidu.com/s/1UgPNYprBgJrc25v5ushWxQ?pwdu12a MacOS 11.0 提取码:y77y 如不能点击跳转请复制此链接到浏览器打开:https://pan.baidu.com/s/1srmibmCi2T7UVGvHkCzGKA?pwdy7…...
算法之位运算
前言 位运算在我们的学习中占有很重要的地位,从二进制中数的存储等都需要我们进行位运算 一、位运算复习 1.位运算复习 按位与(&):如果两个相应的二进制位都为1,则该位的结果值才为1,否则为0 按位或( | ):如果…...
flask使用Flask-Mail实现邮件发送
Flask-Mail可以实现邮件的发送,并且可以和 Flask 集成,让我们更方便地实现此功能。 1、安装 使用pip安装: $ pip install Flask-Mail或下载源码安装: $ git clone https://github.com/mattupstate/flask-mail.git $ cd flask-…...
React refers to UMD global, but the current file is a module vite初始化react项目
vite搭建react项目 初始化项目 npm create vite 在执行完上面的命令后,npm 首先会自动下载create-vite这个第三方包,然后执行这个包中的项目初始化逻辑。输入项目名称之后按下回车,此时需要选择构建的前端框架: ✔ Project na…...
vscode 调试 ROS2
1、在下列目录同层级找到.vscode文件夹 . ├── build ├── install ├── log └── src 2、 安装ros插件 3、创建tasks.json文件,添加下列内容 //代替命令行进行编译 {"version": "2.0.0","tasks": [{"label": &…...
TuyaOS开发学习笔记(2)——NB-IoT开发SDK架构、运行流程
一、SDK架构 1.1 架构框图 基于 TuyaOS 系统,可以裁剪得到的适用于 NB-IoT 协议产品接入的 SDK。SDK 将设备配网、上下行数据通信、产测授权、固件 OTA 升级等接口进行封装,并提供相关函数。 1.2 目录结构 1.2.1 TuyaOS目录说明 adapter:T…...
Qt应用开发(基础篇)——普通按钮类 QPushButton QCommandLinkButton
一、前言 QPushButton类继承于QAbstractButton,是一个命令按钮的小部件。 按钮基类 QAbstractButton 按钮或者命令按钮是所有图形界面框架最常见的部件,当按下按钮的时候触发命令、执行某些操作或者回答一个问题,典型的按钮有OK,A…...
Data Structures Fan(cf)
考察异或运算以及前缀和 题意大概:给你一个长度为n的a数组,一个长度为n的01字符串,会询问q次 当x的值为1 给出 l r 将 l r 区间中的0 改变为1,1改变为0 。当x的值为2是 若随后的数为0 则输出当前字符串中 是0 的a数组中的数异或 …...
石家庄做网站汉狮网络/2023年7月最新新闻摘抄
缺省情况下,应用程序使用缓冲池 IBMDEFAULTBP,它是在创建数据库时创建的。当 SYSCAT.BUFFERPOOLS 目录表中该缓冲池的 NPAGES 值为 -1 时,DB2 数据库配置参数 BUFFPAGE 控制着缓冲池的大小。否则会忽略 BUFFPAGE 参数,并且用 NPAG…...
赣州网站seo/南京seo优化
https://download.csdn.net/download/weixin_57836618/72364964...
新能源电动汽车价格/济南seo外包公司
前言 入职第一天 — 无聊(小抱怨) 目前已经找到了不错的实习岗位,所以这几天,我想把自己的面试经验写一下 面试过程 如何找到岗位 1、去boss直聘之类的平台(相对于智联我更喜欢boss,真的,不…...
宝鸡网站建设公司电话/app关键词优化
VC具有调试功能,安装的时候默认是作为当前系统的即时调试器来安装的 也就是说系统中的程序崩溃的时候,即时调试器就会激活并调试崩溃的程序 你不需要这种功能的话完全可以禁止它 两种办法,优先使用第一种,不行的话再用第二种: 1.在vc中设置(Visual C 6.0) 打开vc环境,菜单Tools…...
设计公司做网站价格/百度平台商家
问题描述 我想访问一个需要用户名/密码的URL。我想尝试用 curl 来访问它。现在我正在做一些事情: curl http://api.somesite.com/test/blah?something123我收到一个错误。我想我需要指定一个用户名和密码以及上述命令。 我怎样才能做到这一点? 最佳解决…...
wordpress 锚点插件/seo入门基础知识
心脏刺激器市场的企业竞争态势 该报告涉及的主要国际市场参与者有Biosensor、Biotronik、Boston Scientific、Braile Biomedica、Cameron Health、GE Healthcare、Lepu Medical Technology、Life Support Systems、Oscor、Osypka Medical、Sorin、Vitatron等。这些参与者的市场…...