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

Zephyr 消息队列

文章目录

  • 简介
  • 数据结构
    • k_msgq
  • 定义消息队列
  • 发送消息
    • k_msgq_put
  • 接收消息
    • k_msgq_get
  • wait_q 的双重身份
  • 清理消息队列
    • k_msgq_cleanup
  • 重置消息队列
    • k_msgq_purge
  • 读取数据
    • k_msgq_peek
    • k_msgq_peek_at
  • 缓冲区容量
    • k_msgq_num_free_get
    • k_msgq_num_used_get

简介

  • message queue 用于中断和线程之间进行数据传输的一项服务,其本质是一个环形缓冲区,例如串口驱动中通常会使用环形缓冲区来接收数据,缓冲区中每一项的大小是固定的。
  • Zephyr 中的 msgq 是消息队列的具体实现,它需要提供一个缓冲区用于存储数据,缓冲区的大小是缓存项大小的整数倍,与 Zephyr 中的 queue 不同,消息队列写入和读取会拷贝数据。

数据结构

k_msgq

  • k_msgq 是 Zephyr 中用于描述 消息队列的一个结构体,其成员变量包含了实现消息队列的必要元素:
struct k_msgq {/** Message queue wait queue */_wait_q_t wait_q;/** Lock */struct k_spinlock lock;/** Message size */size_t msg_size;/** Maximal number of messages */uint32_t max_msgs;/** Start of message buffer */char *buffer_start;/** End of message buffer */char *buffer_end;/** Read pointer */char *read_ptr;/** Write pointer */char *write_ptr;/** Number of used messages */uint32_t used_msgs;_POLL_EVENT;/** Message queue */uint8_t flags;SYS_PORT_TRACING_TRACKING_FIELD(k_msgq)
};
  • wait_q
    • 保存因缓冲区为空被阻塞的接收线程,或者是因缓冲区满被阻塞的发送线程。
  • lock
    • 多线程互斥
  • msg_size
    • 消息队列中每一项的大小
  • max_msgs
    • 消息队列中能容纳消息的最大数量
  • buffer_start
    • 缓冲区起始地址
  • buffer_end
    • 缓冲区结束地址
  • read_ptr
    • 类似于环形缓冲区中的 head,每读取一次地址向后偏移固定长度。
  • write_ptr
    • 类似于环形缓冲区中的 tail,每写入一次地址向后偏移固定长度。
  • used_msgs
    • 已经存放的消息条数,每读取一次减1,写入一次加1。
  • flags
    • 消息队列支持两种初始化方式,一种是用户提供缓冲区,另一种是由系统分配缓冲区,当选择由系统分配缓冲区时,在消息队列销毁时需要回收内存,为了标记内存来源,因此使用 flags 保存标志,下面是对应的标志位。
#define K_MSGQ_FLAG_ALLOC	BIT(0)

定义消息队列

  • 消息队列包含3个重要属性,单条消息的大小,缓冲区最大消息容量,缓冲区对齐大小。
  • 定义一个静态缓冲区可使用 K_MSGQ_DEFINE 宏
#define K_MSGQ_DEFINE(q_name, q_msg_size, q_max_msgs, q_align)		\static char __noinit __aligned(q_align)				\_k_fifo_buf_##q_name[(q_max_msgs) * (q_msg_size)];	\STRUCT_SECTION_ITERABLE(k_msgq, q_name) =			\Z_MSGQ_INITIALIZER(q_name, _k_fifo_buf_##q_name,	\q_msg_size, q_max_msgs)
  • 还可通过函数 k_msgq_init 初始化消息队列,该函数需要提供环形缓冲区和一个 k_msgq 对象:
struct msg_item_type { int val;
};static char __aligned(4) s_msgq_buffer[10 * sizeof(struct msg_item_type )];
static struct k_msgq s_msgq;k_msgq_init(&s_msgq, s_msgq_buffer, sizeof(struct msg_item_type ), 10);
  • k_msgq_init 的另一个版本是 k_msgq_alloc_init,它可以从系统中动态分配一段空间作为环形缓冲区:
static struct k_msgq s_msgq;
k_msgq_alloc_init(&s_msgq, sizeof(struct msg_item_type ), 10);

发送消息

k_msgq_put

  • 消息队列的消息发送函数:
    • int k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
  • 该函数的实现函数为 z_impl_k_msgq_put
int z_impl_k_msgq_put(struct k_msgq *msgq, const void *data, k_timeout_t timeout)
{/* 当 k_msgq_put 在中断中调用时,timeout 不等于 K_NO_WAIT 会触发断言 */__ASSERT(!arch_is_in_isr() || K_TIMEOUT_EQ(timeout, K_NO_WAIT), "");struct k_thread *pending_thread;k_spinlock_key_t key;int result;key = k_spin_lock(&msgq->lock);SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_msgq, put, msgq, timeout);/* 消息队列未满时,如果等待队列中存在等待线程,* 可将数据写入 swap_data 指向的内存中(线程在等待时已将缓存首地址放入swap_data),* 反之如果没有线程处于等待状态,将数据放入环形缓冲区中*/if (msgq->used_msgs < msgq->max_msgs) {/* message queue isn't full */pending_thread = z_unpend_first_thread(&msgq->wait_q);if (pending_thread != NULL) {SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, put, msgq, timeout, 0);/* give message to waiting thread */(void)memcpy(pending_thread->base.swap_data, data,msgq->msg_size);/* wake up waiting thread */arch_thread_return_value_set(pending_thread, 0);z_ready_thread(pending_thread);z_reschedule(&msgq->lock, key);return 0;} else {/* put message in queue */(void)memcpy(msgq->write_ptr, data, msgq->msg_size);msgq->write_ptr += msgq->msg_size;if (msgq->write_ptr == msgq->buffer_end) {msgq->write_ptr = msgq->buffer_start;}msgq->used_msgs++;
#ifdef CONFIG_POLLhandle_poll_events(msgq, K_POLL_STATE_MSGQ_DATA_AVAILABLE);
#endif /* CONFIG_POLL */}result = 0;} /* 队列满且等待时间为0,返回 -ENOMSG */else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {/* don't wait for message space to become available */result = -ENOMSG;} /* 队列满且等待时间不为0,将当前线程的 swap_data 指向数据首地址,然后将调用线程挂起 */else {SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_msgq, put, msgq, timeout);/* wait for put message success, failure, or timeout */_current->base.swap_data = (void *) data;result = z_pend_curr(&msgq->lock, key, &msgq->wait_q, timeout);SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, put, msgq, timeout, result);return result;}SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, put, msgq, timeout, result);k_spin_unlock(&msgq->lock, key);return result;
}
  • k_msgq_put 用于将消息写入环形缓冲区,该函数允许在中断中使用,在中断使用时 timeout 必须是0.
  • 当等待队列非空时,可将数据直接拷贝至 tcb 中 swap_data 指向的内存中,相比放入队列后再从队列中将数据拷贝到用户空间,这种方式提高了效率。
  • 只有当等待队列为空时,才会将数据暂存入环形缓冲区中,等待线程读取。

接收消息

k_msgq_get

  • 消息队列的消息接收函数:
    • int k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout)
  • 该函数的实现函数为 z_impl_k_msgq_get
int z_impl_k_msgq_get(struct k_msgq *msgq, void *data, k_timeout_t timeout)
{__ASSERT(!arch_is_in_isr() || K_TIMEOUT_EQ(timeout, K_NO_WAIT), "");k_spinlock_key_t key;struct k_thread *pending_thread;int result;key = k_spin_lock(&msgq->lock);SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_msgq, get, msgq, timeout);/* 当环形缓冲区中不为空时,从中读取一条消息 */if (msgq->used_msgs > 0U) {/* take first available message from queue */(void)memcpy(data, msgq->read_ptr, msgq->msg_size);msgq->read_ptr += msgq->msg_size;if (msgq->read_ptr == msgq->buffer_end) {msgq->read_ptr = msgq->buffer_start;}msgq->used_msgs--;/* 从等待队列中获取一个因缓冲区满,无法写入数据而被挂起的线程 */pending_thread = z_unpend_first_thread(&msgq->wait_q);if (pending_thread != NULL) {SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_msgq, get, msgq, timeout);/* 将线程需写入的数据放入缓冲区中 */(void)memcpy(msgq->write_ptr, pending_thread->base.swap_data,msgq->msg_size);msgq->write_ptr += msgq->msg_size;if (msgq->write_ptr == msgq->buffer_end) {msgq->write_ptr = msgq->buffer_start;}msgq->used_msgs++;/* 唤醒该线程 */arch_thread_return_value_set(pending_thread, 0);z_ready_thread(pending_thread);z_reschedule(&msgq->lock, key);SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, get, msgq, timeout, 0);return 0;}result = 0;}/* 缓冲区中没有数据,且等待时间为0,返回 -ENOMSG */else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {/* don't wait for a message to become available */result = -ENOMSG;} /* 缓冲区中没有数据,且等待时间不为0,将调用线程添加到等待队列并挂起 */else {SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_msgq, get, msgq, timeout);/* wait for get message success or timeout */_current->base.swap_data = data;result = z_pend_curr(&msgq->lock, key, &msgq->wait_q, timeout);SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, get, msgq, timeout, result);return result;}SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, get, msgq, timeout, result);k_spin_unlock(&msgq->lock, key);return result;
}
  • k_msgq_get 首先会判断缓冲区中是否有数据,如果缓冲区中有数据,会从中取出一条数据拷贝到用户空间。
  • 缓冲区中有数据就意味着等待队列中可能存在因缓冲区满无法写入而被阻塞的线程,此时由于从缓冲区中读出一条数据,可以进行写入,便将被挂起线程中未写入的数据拷贝到缓冲区中,同时解除挂起。
  • 如果缓冲区无数据且等待时间为0,返回 -ENOMSG。
  • 如果缓冲区无数据且等待时间不为0,将当前线程挂起。

wait_q 的双重身份

  • 消息队列与其他 IPC 对象中的 wait_q 有所不同,以Mutex为例,只有当加锁时需要进入等待,因此 wait_q 中存放的一定是因加锁被阻塞的线程。
  • 而在消息队列中无论是发送数据还是接收数据都可能进入等待,并且它们使用的是同一个等待队列。
  • 首先来看一下进入等待队列的条件:
    • 发送线程在缓冲区满,且等待时间不为0时,将被放入等待队列中。
    • 接收线程在缓冲区空,且等待时间不为0时,将被放入等待队列中。
  • 两种情况不可能同时存在,因此可以共用一个等待队列。

清理消息队列

k_msgq_cleanup

  • 清理消息队列主要作用是,回收系统分配的缓冲区。
  • 为了安全,在清理时会检查消息队列是否仍然在被使用
int k_msgq_cleanup(struct k_msgq *msgq)
{SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_msgq, cleanup, msgq);CHECKIF(z_waitq_head(&msgq->wait_q) != NULL) {SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, cleanup, msgq, -EBUSY);return -EBUSY;}if ((msgq->flags & K_MSGQ_FLAG_ALLOC) != 0U) {k_free(msgq->buffer_start);msgq->flags &= ~K_MSGQ_FLAG_ALLOC;}SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_msgq, cleanup, msgq, 0);return 0;
}

重置消息队列

k_msgq_purge

  • void k_msgq_purge(struct k_msgq *msgq)
void z_impl_k_msgq_purge(struct k_msgq *msgq)
{k_spinlock_key_t key;struct k_thread *pending_thread;key = k_spin_lock(&msgq->lock);SYS_PORT_TRACING_OBJ_FUNC(k_msgq, purge, msgq);/* 唤醒等待队列中被阻塞的线程,然后返回-ENOMSG */while ((pending_thread = z_unpend_first_thread(&msgq->wait_q)) != NULL) {arch_thread_return_value_set(pending_thread, -ENOMSG);z_ready_thread(pending_thread);}/* 然后将缓冲区中的数据清空 */msgq->used_msgs = 0;msgq->read_ptr = msgq->write_ptr;z_reschedule(&msgq->lock, key);
}
  • 该函数用于清空消息队列,如果有线程因数据发送或接收而进入等待,同时会将被挂起的线程唤醒。

读取数据

k_msgq_peek

  • int k_msgq_peek(struct k_msgq *msgq, void *data)
  • 该函数以先进先出的方式从消息队列中读取一条消息,但是不会修改 read_str 将队列项移出队列,因此该操作无需等待。

k_msgq_peek_at

  • int k_msgq_peek_at(struct k_msgq *msgq, void *data, uint32_t idx)
  • k_msgq_peek_at 是 k_msgq_peek 的另一个版本,以 read_str 作为第一项,向后偏移 idx 项之后的数据,将其拷贝到 data 指向的内存中。

缓冲区容量

k_msgq_num_free_get

  • uint32_t k_msgq_num_free_get(struct k_msgq *msgq)
  • k_msgq_num_free_get 用于获取缓冲区中剩余容量,返回值代表可存储消息的数量。

k_msgq_num_used_get

  • uint32_t k_msgq_num_used_get(struct k_msgq *msgq)
  • k_msgq_num_used_get 用于获取已经使用的容量,即 used_msgs 的值。

相关文章:

Zephyr 消息队列

文章目录 简介数据结构k_msgq 定义消息队列发送消息k_msgq_put 接收消息k_msgq_get wait_q 的双重身份清理消息队列k_msgq_cleanup 重置消息队列k_msgq_purge 读取数据k_msgq_peekk_msgq_peek_at 缓冲区容量k_msgq_num_free_getk_msgq_num_used_get 简介 message queue 用于中…...

Jenkins自动化部署实例讲解

文章目录 前言实例讲解基本环境全局工具配置创建任务任务配置源码管理构建步骤&#xff08;Build Steps&#xff09;第一步&#xff1a;调用Maven第二步&#xff1a;执行shell启动容器 后记 前言 你平常在做自己的项目时&#xff0c;是否有过部署项目太麻烦的想法&#xff1f;…...

RK356X 解除UVC摄像头预览分辨率1080P限制

平台 RK3566 Android 11 概述 UVC&#xff1a; USB video class&#xff08;又称为USB video device class or UVC&#xff09;就是USB device class视频产品在不需要安装任何的驱动程序下即插即用&#xff0c;包括摄像头、数字摄影机、模拟视频转换器、电视卡及静态视频相机…...

English Learning - L2-14 英音地道语音语调 重音技巧 2023.04.10 周一

English Learning - L2-14 英音地道语音语调 重音技巧 2023.04.10 周一 课前热身重音日常表达节奏单词全部重读的句子间隔时间非重读单词代词和缩约词助动词声临其境语调预习 课前热身 学习目标 重音 重弱突出&#xff0c;重音突出核心表达的意思 重音是落在重读单词上&…...

3.6 n维随机变量

学习目标&#xff1a; 学习n维随机变量需要掌握一定的数学知识&#xff0c;包括多元微积分、线性代数和概率论等。要学习n维随机变量&#xff0c;我会采取以下步骤&#xff1a; 复习相关的数学知识&#xff1a;首先&#xff0c;我会复习多元微积分、线性代数和概率论的基本知…...

JavaSE学习进阶day06_02 Set集合和Set接口

第二章 Set系列集合和Set接口 Set集合概述&#xff1a;前面学习了Collection集合下的List集合&#xff0c;现在继续学习它的另一个分支&#xff0c;Set集合。 set系列集合的特点&#xff1a; Set接口&#xff1a; java.util.Set接口和java.util.List接口一样&#xff0c;同样…...

基于matlab分析卫星星座对通信链路的干扰

一、前言 此示例说明如何分析从中地球轨道 &#xff08;MEO&#xff09; 中的卫星星座到位于太平洋的地面站的下行链路上的干扰。干扰星座由低地球轨道&#xff08;LEO&#xff09;的40颗卫星组成。此示例确定下行链路闭合的时间、载波噪声加干扰比以及链路裕量。 此示例需要卫…...

Python中的异常——概述和基本语法

Python中的异常——概述和基本语法 摘要&#xff1a;Python中的异常是指在程序运行时发生的错误情况&#xff0c;包括但不限于除数为0、访问未定义变量、数据类型错误等。异常处理机制是Python提供的一种解决这些错误的方法&#xff0c;我们可以使用try/except语句来捕获异常并…...

Tomcat 部署与优化

1. Tomcat概述 Tomcat是Java语言开发的&#xff0c;Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;是Apache软件基金会的Jakarta项目中的一个核心项目&#xff0c;由Apache、Sun和其他一些公司及个人 共同开发而成。Tomcat属于轻量级应用服务器&#xff0c;在…...

多模态之论文笔记ViLT

文章目录 ViLT: Vision-and-Language Transformer Without Convolution or Region Supervision一. 简介1.1 摘要1.2 文本编码器&#xff0c;图像编码器&#xff0c;特征交互复杂度分析1.2 特征交互方式分析1.3 图像特征提取分析 二. 方法 Vision-and-Language Transformer2.1.方…...

微服务架构下认证和鉴权理解

认证和鉴权 从单体应用到微服务架构&#xff0c;优势很多&#xff0c;但是并不是代表着就没有一点缺点了。 微服务架构&#xff0c;意味着每个服务都是松散耦合的。因此&#xff0c;作为软件工程师和架构师&#xff0c;我们在分布式架构中面临着安全挑战。微服务对外开放的端…...

Qt 网络编程之美:探索 URL、HTTP、服务发现与请求响应

Qt 网络编程之美&#xff1a;探索 URL、HTTP、服务发现与请求响应&#xff08;The Beauty of Qt Network Programming: Exploring URL, HTTP, Service Discovery, and Request-Response 引言&#xff08;Introduction&#xff09;QUrl 类&#xff1a;构建和解析 URL&#xff08…...

毕业2年,跳槽到下一个公司就25K了,厉害了···

本人本科就读于某普通院校&#xff0c;毕业后通过同学的原因加入软件测试这个行业&#xff0c;角色也从测试小白到了目前的资深工程师&#xff0c;从功能测试转变为测试开发&#xff0c;并顺利拿下了某二线城市互联网企业的Offer&#xff0c;年薪 30W 。 选择和努力哪个重要&a…...

设计模式 -- 适配器模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…...

STM32之增量式编码器电机测速

STM32之增量式编码器电机测速 编码器编码器种类按监测原理分类光电编码器霍尔编码器 按输出信号分类增量式编码器绝对式编码器 编码器参数分辨率精度最大响应频率信号输出形式 编码器倍频 STM32的编码器模式编码器模式编码器的计数方向仅在TI1计数电机正转&#xff0c;向上计数…...

一图看懂 xlsxwriter 模块:用于创建 Excel .xlsx 文件, 资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 xlsxwriter 模块&#xff1a;用于创建 Excel .xlsx 文件, 资料整理笔记&#xff08;大全&#xff09; 摘要模块图类关系图模块全展开【xlsxwriter】统计常量模块1 xlsxwrit…...

【社区图书馆】NVMe协议的命令

声明 主页:元存储的博客_CSDN博客 依公开知识及经验整理,如有误请留言。 个人辛苦整理,付费内容,禁止转载。 内容摘要 前言 命令由host提交到内存中的SQ队列中,更新TDBxSQ后,NVMe控制器通过DMA的方式将SQ中的命令(怎么取,如何取,取多少,因设计而异)取到控制器缓冲区…...

Nginx网站服务

Nginx概述 Nginx 是开源、高性能、高可靠、低资源消耗的 Web 和反向代理服务器&#xff0c;而且支持热部署&#xff0c;几乎可以做到 7 * 24 小时不间断运行&#xff0c;即使运行几个月也不需要重新启动&#xff0c;还能在不间断服务的情况下对软件版本进行热更新。对HTTP并发…...

第八篇 Spring 集成JdbcTemplate

《Spring》篇章整体栏目 ————————————————————————————— 【第一章】spring 概念与体系结构 【第二章】spring IoC 的工作原理 【第三章】spring IOC与Bean环境搭建与应用 【第四章】spring bean定义 【第五章】Spring 集合注入、作用域 【第六章】…...

双塔模型:微软DSSM模型浅析

1.背景 DSSM是Deep Structured Semantic Model (深层结构语义模型) 的缩写&#xff0c;即我们通常说的基于深度网络的语义模型&#xff0c;其核心思想是将query和doc映射到到共同维度的语义空间中&#xff0c;通过最大化query和doc语义向量之间的余弦相似度&#xff0c;从而训…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

boost::filesystem::path文件路径使用详解和示例

boost::filesystem::path 是 Boost 库中用于跨平台操作文件路径的类&#xff0c;封装了路径的拼接、分割、提取、判断等常用功能。下面是对它的使用详解&#xff0c;包括常用接口与完整示例。 1. 引入头文件与命名空间 #include <boost/filesystem.hpp> namespace fs b…...

LangChain【6】之输出解析器:结构化LLM响应的关键工具

文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器&#xff1f;1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...

【1】跨越技术栈鸿沟:字节跳动开源TRAE AI编程IDE的实战体验

2024年初&#xff0c;人工智能编程工具领域发生了一次静默的变革。当字节跳动宣布退出其TRAE项目&#xff08;一款融合大型语言模型能力的云端AI编程IDE&#xff09;时&#xff0c;技术社区曾短暂叹息。然而这一退场并非终点——通过开源社区的接力&#xff0c;TRAE在WayToAGI等…...