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

dify实现原理分析-rag-数据检索的实现

数据检索的总体执行步骤

数据检索总体步骤如下:

输入验证
模型初始化
策略选择: 1.单线程检索 2.多线程检索
数据集筛选: 选择符合条件的数据集
执行检索: 使用单线程或多线程检索来查询数据
结果处理: 结果选择和格式化处理
返回格式化内容: 最终返回一个结果字符串

数据检索是在DatasetRetrieval.retrieve函数中实现的,主要实现逻辑分为以下几步:

  1. 检查输入的模型、数据集id列表等是否为空;

  2. 获取模型实例,并把它转换成LargeLanguageModel对象;

  3. 获取模型实例,并获取模型的元数据,主要是模型的各种参数,以及认证参数等。若模型的元数据为空,直接返回None。

  4. 默认情况下,规划路由策略被设置为 REACT_ROUTER。如果模型支持工具调用(TOOL_CALL)或多重工具调用(MULTI_TOOL_CALL),则将规划策略更改为 ROUTER;

  5. 筛选可用的数据集:若数据集为空,或数据集不可用则过滤掉数据集;后续的数据检索,会从这些可用数据集中来进行检索。

  6. 根据配置选择单线程(RetrieveStrategy.SINGLE)或多线程检索(RetrieveStrategy.MULTIPLE),获取检索到的document列表;这里只是设置检索的参数,而这两种检索方式都会调用检索服务的RetrievalService.retrieve(…)函数来检索符合条件的数据集。

  7. 处理dify提供者的document:使用回调函数返回检索结果,根据分数对检索结果进行排序,并返回格式化后的字符串。

    1)获取每个文档的分数(score)的值

    2)查询状态为completed,且可用,doc_id在检索出来的文档列表中的DocumentSegment列表

    3)若segment(文档块)不为空。

    ​ 3.1) 获取segment的id和位置(确定文档内容的读取位置)

    ​ 3.2) 按id所在的position(位置)排序,若id不在字典中排到最后(无穷大inf)

    ​ 3.3) 遍历排好序的segment:根据条件构建新的列表,然后进行一下操作:

    ​ a) 检查每个segment是否包含answer

    ​ b) 包含:构建一个包含问题和答案的字符串

    ​ c) 不包含:则只构建一个问题的字符串

    ​ 3.4) 对已排好序的segment进行遍历

    ​ 3.5) 获取segment对应的dataset_id对应的dataset

    ​ 3.6) 获取segment.document_id对应的document

  8. 使用回调函数返回检索结果,根据分数对检索结果进行排序,并返回格式化后的字符串。

检索的详细执行流程

数据检索的函数声明如下:

class DatasetRetrieval:def __init__(self, application_generate_entity=None):self.application_generate_entity = application_generate_entitydef retrieve(self,app_id: str,user_id: str,tenant_id: str,model_config: ModelConfigWithCredentialsEntity,config: DatasetEntity,query: str,invoke_from: InvokeFrom,show_retrieve_source: bool,hit_callback: DatasetIndexToolCallbackHandler,message_id: str,memory: Optional[TokenBufferMemory] = None,) -> Optional[str]:"""Retrieve dataset.:param app_id: app_id:param user_id: user_id:param tenant_id: tenant id:param model_config: model config:param config: dataset config:param query: query:param invoke_from: invoke from:param show_retrieve_source: show retrieve source:param hit_callback: hit callback:param message_id: message id:param memory: memory:return:"""

该函数的详细实现逻辑如下:

  1. 检查数据集id列表,若数据集id列表为空,则直接返回None;
        # 检查输入的模型、数据集等是否有效。dataset_ids = config.dataset_idsif len(dataset_ids) == 0:return None
  1. 根据模型配置来获取和构建模型实例对象,并获取模型的元数据(各种参数)
        model_type_instance = model_config.provider_model_bundle.model_type_instancemodel_type_instance = cast(LargeLanguageModel, model_type_instance)# 获取模型实例model_manager = ModelManager()model_instance = model_manager.get_model_instance(tenant_id=tenant_id, model_type=ModelType.LLM, provider=model_config.provider, model=model_config.model)
  1. 设置计划策略,默认情况下计划策略是:PlanningStrategy.REACT_ROUTER,若模型特征支持工具调用:ModelFeature.TOOL_CALL或MULTI_TOOL_CALL,则把计划策略设置成:ROUTER,即:planning_strategy = PlanningStrategy.ROUTER
        # 默认情况下,规划策略被设置为 REACT_ROUTER。planning_strategy = PlanningStrategy.REACT_ROUTER# 检查模型的特性(features)。# 如果模型支持工具调用(TOOL_CALL)或多重工具调用(MULTI_TOOL_CALL),则将规划策略更改为 ROUTER。features = model_schema.features# 检查模型是否支持工具调用,若支持计划策略设置为ROUTERif features:if ModelFeature.TOOL_CALL in features or ModelFeature.MULTI_TOOL_CALL in features:planning_strategy = PlanningStrategy.ROUTERavailable_datasets = []
  1. 筛选可用数据集:遍历参数中的dataset_ids列表,从数据库中查询对应id的数据集,过滤掉数据集可用文档为0的和数据集的provide为external的数据集。
        # 筛选可用的数据集。for dataset_id in dataset_ids:# 查询对应id列表的数据集dataset = db.session.query(Dataset).filter(Dataset.tenant_id == tenant_id, Dataset.id == dataset_id).first()# 数据集为空,pass掉if not dataset:continue# 数据集不可用,pass掉if dataset and dataset.available_document_count == 0 and dataset.provider != "external":continue# 把数据集添加到可用数据集列表中available_datasets.append(dataset)
  1. 根据配置选择单线程(single_retrieve)或多线程(multiple_retrieve)检索来检索document,得到结果document列表:all_documents。
        if retrieve_config.retrieve_strategy == DatasetRetrieveConfigEntity.RetrieveStrategy.SINGLE:all_documents = self.single_retrieve(...)elif retrieve_config.retrieve_strategy == DatasetRetrieveConfigEntity.RetrieveStrategy.MULTIPLE:all_documents = self.multiple_retrieve(...)
  1. 从all_documents中抽取出:dify_documents(provider == “dify”)和external_documents(provider == “external”)的结果。处理外部和Dify提供者的document,生成相应的上下文和资源信息。
        # 得到不同提供者的documentdify_documents = [item for item in all_documents if item.provider == "dify"]external_documents = [item for item in all_documents if item.provider == "external"]
  1. 处理结果队列dify_documents,步骤如下:

(1)收集评分信息(document_score_list):通过检查 dify_documents 列表中每个文档片段的 score 元数据,构建一个字典 document_score_list,其中键是文档 ID,值是对应的评分。

            # 获取每个文档的分数(score)的值for item in dify_documents:if item.metadata.get("score"):document_score_list[item.metadata["doc_id"]] = item.metadata["score"]

(2)过滤和排序文档片段:根据给定的 dataset_ids 和一些状态条件(如 status=completed, enabled=True),从数据库中查询相关的文档片段(DocumentSegment)。然后将这些文档片段按其在原始列表中的索引顺序进行排序。

(3)构建文档上下文(document_context_list):对于每个排序后的文档片段,创建一个 DocumentContext 实例,并将其添加到 document_context_list 中。如果文档片段包含答案(answer),则将答案与问题一起作为一个字符串存储在内容字段中;否则,只存储问题。

             # 获取segment的id和位置(确定文档内容的读取位置)index_node_id_to_position = {id: position for position, id in enumerate(index_node_ids)}# 按id所在的position(位置)排序,若id不在字典中排到最后(无穷大inf)sorted_segments = sorted(segments, key=lambda segment: index_node_id_to_position.get(segment.index_node_id, float("inf")))# 遍历排好序的segment:根据条件构建新的列表for segment in sorted_segments:# 检查每个segment是否包含answerif segment.answer: # 包含:构建一个包含问题和答案的字符串document_context_list.append(DocumentContext(content=f"question:{segment.get_sign_content()} answer:{segment.answer}",score=document_score_list.get(segment.index_node_id, None),))else: # 不包含:则只构建一个问题的字符串document_context_list.append(DocumentContext(content=segment.get_sign_content(),score=document_score_list.get(segment.index_node_id, None),))

(4)构建检索资源(retrieval_resource_list):如果设置了 show_retrieve_source 标志为真,对于每个排序后的文档片段,查询相关的数据集(dataset)和文档(document)信息。创建一个 source 字典,其中包含数据集、文档的详细信息以及文档片段的相关属性(如评分、命中次数、词数等)。将包含详细信息的 source 字典添加到 retrieval_resource_list 中。

 	          if show_retrieve_source: # 设置了展示检索源的标识			for segment in sorted_segments: # 遍历排序segment# 获取segment对应的dataset_id对应的datasetdataset = Dataset.query.filter_by(id=segment.dataset_id).first()# 获取segment.document_id对应的documentdocument = DatasetDocument.query.filter(DatasetDocument.id == segment.document_id,...).first()# 若2者同时存在if dataset and document:# 构建source字典,包含各种信息source = {"dataset_id": dataset.id,"dataset_name": dataset.name,"document_id": document.id,"document_name": document.name,"data_source_type": document.data_source_type,"segment_id": segment.id,"retriever_from": invoke_from.to_source(),"score": document_score_list.get(segment.index_node_id, 0.0),}...# 若segment的回答不为空,则获取:question与answerif segment.answer:source["content"] = f"question:{segment.content} \nanswer:{segment.answer}"else: # 仅获取questionsource["content"] = segment.content# 将源字典添加到retrieval源列表中retrieval_resource_list.append(source)
  1. 使用回调函数返回检索结果,根据分数对检索结果进行排序,并返回格式化后的字符串。
        # 使用回调函数返回检索结果,根据分数对检索结果进行排序,并返回格式化后的字符串。                   if hit_callback and retrieval_resource_list:# 根据segment所在doc_id的分数进行排序retrieval_resource_list = sorted(retrieval_resource_list, key=lambda x: x.get("score") or 0.0, reverse=True)# 获取检索列表中的位置参数for position, item in enumerate(retrieval_resource_list, start=1):item["position"] = positionhit_callback.return_retriever_resource_info(retrieval_resource_list)
  1. 按分数进行排序,并把文档内容合并在一个字符串中返回
if document_context_list:# 按分数进行排序,并把文档内容合并在一个字符串中返回document_context_list = sorted(document_context_list, key=lambda x: x.score or 0.0, reverse=True)return str("\n".join([document_context.content for document_context in document_context_list]))

总结

总结一下数据检索的主要步骤:(1)参数验证和模型选择;(2)检索策略选择:单线程或多线程检索(3)结果筛选和处理(4)结果合并和格式化处理,然后返回。

不管是单线程检索还是多线程检索,都会调用检索服务的retrieve函数来实现检索功能,检索服务的检索具体实现会在后面的文章中进行分析。

相关文章:

dify实现原理分析-rag-数据检索的实现

数据检索的总体执行步骤 数据检索总体步骤如下: #mermaid-svg-YCRNdSE7T1d0Etyj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-YCRNdSE7T1d0Etyj .error-icon{fill:#552222;}#mermaid-svg-YCRNdSE7T1d…...

20个整流电路及仿真实验汇总

0、 前言 以下是关于“20个整流电路及仿真实验汇总”的前言部分: 在现代电力电子技术领域,整流电路作为将交流电(AC)转换为直流电(DC)的关键电路,广泛应用于各类电源设计、信号处理以及电力电子设备中。整流电路不仅能够为电子设备提供稳定的直流电源,还在电力传输、…...

CVE-2020-0796永恒之蓝2.0(漏洞复现)

目录 前言 产生原因 影响范围 漏洞复现 复现环境 复现步骤 防御措施 总结 前言 在网络安全的战场上,漏洞一直是攻防双方关注的焦点。CVE-2020-0796,这个被称为 “永恒之蓝 2.0” 的漏洞,一度引起了广泛的关注与担忧。它究竟是怎样的…...

爬虫基础(一)HTTP协议 :请求与响应

前言 爬虫需要基础知识,HTTP协议只是个开始,除此之外还有很多,我们慢慢来记录。 今天的HTTP协议,会有助于我们更好的了解网络。 一、什么是HTTP协议 (1)定义 HTTP(超文本传输协议&#xff…...

拼车(1094)

1094. 拼车 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a; class Solution { public:bool carPooling(vector<vector<int>>& trips, int capacity) {uint32_t passenger_cnt 0;//将原数据按照from排序auto func_0 [](vector<int> & …...

Ubuntu全面卸载mysql

如果你已经看到whereis mysql输出了与MySQL相关的路径&#xff0c;说明MySQL仍然存在于系统中。要卸载MySQL&#xff0c;可以按照以下步骤操作&#xff0c;确保完全删除所有相关的文件和配置&#xff1a; 1. 停止MySQL服务 首先&#xff0c;停止MySQL服务&#xff1a; sudo …...

@Inject @Qualifier @Named

Inject Qualifier Named 在依赖注入&#xff08;DI&#xff09;中&#xff0c;Inject、Qualifier 和 Named 是用于管理对象创建和绑定的关键注解。以下是它们的用途、依赖配置和代码示例的详细说明&#xff1a; 1. 注解的作用 Inject&#xff1a;标记需要注入的构造函数、字段…...

OpenHarmonyOS 3.2 编译生成的hap和app文件的名称如何配置追加版本号?

找了一圈发现官方的文档都是最新的&#xff0c;3.2很多API都不支持&#xff0c;比如获取OhosAppContext&#xff0c;通过OhosAppContext来获取应用版本号&#xff0c;最终是通过读取app.json5的文件内容来读取版本号&#xff0c;最终修改entry下的hvigorfile.ts如下&#xff0c…...

初始化mysql报错cannot open shared object file: No such file or directory

报错展示 我在初始化msyql的时候报错&#xff1a;mysqld: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory 解读&#xff1a; libaio包的作用是为了支持同步I/O。对于数据库之类的系统特别重要&#xff0c;因此…...

Vue.js组件开发-实现全屏背景图片滑动切换特效

使用 Vue 实现全屏背景图片滑动切换特效的详细步骤、代码、注释和使用说明。 步骤 创建 Vue 项目&#xff1a;使用 Vue CLI 创建一个新的 Vue 项目。准备图片资源&#xff1a;准备好要用于背景切换的图片&#xff0c;并将它们放在项目的合适目录下。编写 HTML 结构&#xff1…...

AI在自动化测试中的伦理挑战

在软件测试领域&#xff0c;人工智能&#xff08;AI&#xff09;已经不再是遥不可及的未来技术&#xff0c;而是正在深刻影响着测试过程的现实力量。尤其是在自动化测试领域&#xff0c;AI通过加速测试脚本生成、自动化缺陷检测、测试数据生成等功能&#xff0c;极大提升了测试…...

FreeRTOS的任务创建和删除

1&#xff0c;任务创建和删除的API函数 任务的创建和删除本质就是调用FreeRTOS的API函数 动态创建任务&#xff1a; 任务的任务控制块以及任务的栈空间所需的内存&#xff0c;均由 FreeRTOS 从 FreeRTOS 管理的堆中分配。 静态创建任务&#xff1a; 任务的任务控制块以及任务的…...

【C++】STL容器使用与实现详解:vector

文章目录 Ⅰ. vector的介绍和使用一、vector的介绍二、vector的使用 &#xff08;只列出比较重要的&#xff0c;其他的需要时查文档&#xff09;1. vector的定义2. vector iterator&#xff08;迭代器&#xff09;的使用3. vector 容量问题4. vector 增删查改5. 正确释放 vecto…...

【Block总结】动态蛇形卷积,专注于细长和弯曲的局部结构|即插即用

论文信息 标题: Dynamic Snake Convolution based on Topological Geometric Constraints for Tubular Structure Segmentation 作者: 戚耀磊、何宇霆、戚晓明、张媛、杨冠羽 会议: 2023 IEEE/CVF International Conference on Computer Vision (ICCV) 发表时间: 2023年10月…...

物业管理软件引领社区智能化转型提升服务效率与居民生活质量

内容概要 物业管理软件的出现&#xff0c;标志着社区管理方式的一场革命&#xff0c;它不仅仅是一个工具&#xff0c;更是推动智能化转型的关键助力。通过高效的管理功能&#xff0c;物业管理软件在优化服务流程的同时&#xff0c;也提升了居民的生活质量和社区的整体发展活力…...

论文阅读(十三):复杂表型关联的贝叶斯、基于系统的多层次分析:从解释到决策

1.论文链接&#xff1a;Bayesian, Systems-based, Multilevel Analysis of Associations for Complex Phenotypes: from Interpretation to Decision 摘要&#xff1a; 遗传关联研究&#xff08;GAS&#xff09;报告的结果相对稀缺&#xff0c;促使许多研究方向。尽管关联概念…...

线性调整器——耗能型调整器

线性调整器又称线性电压调节器&#xff0c;以下是关于它的介绍&#xff1a; 基本工作原理 线性调整器的基本电路如图1.1(a)所示,晶体管Q1(工作于线性状态,或非开关状态)构成一个连接直流源V和输出端V。的可调电气电阻,直流源V由60Hz隔离变压器&#xff08;电气隔离和整流&#…...

梯度提升用于高效的分类与回归

使用 决策树&#xff08;Decision Tree&#xff09; 实现 梯度提升&#xff08;Gradient Boosting&#xff09; 主要是模拟 GBDT&#xff08;Gradient Boosting Decision Trees&#xff09; 的原理&#xff0c;即&#xff1a; 第一棵树拟合原始数据计算残差&#xff08;负梯度…...

使用Ollama和Open WebUI快速玩转大模型:简单快捷的尝试各种llm大模型,比如DeepSeek r1

Ollama本身就是非常优秀的大模型管理和推理组件&#xff0c;再使用Open WebUI更加如虎添翼&#xff01; Ollama快速使用指南 安装Ollama Windows下安装 下载Windows版Ollama软件&#xff1a;Release v0.5.7 ollama/ollama GitHub 下载ollama-windows-amd64.zip这个文件即可…...

2025年1月个人工作生活总结

本文为 2025年1月工作生活总结。 研发编码 使用sqlite3命令行查询表数据 可以直接使用sqlite3查询数据表&#xff0c;不需进入命令行模式。示例如下&#xff1a; sqlite3 database_name.db "SELECT * FROM table_name;"linux shell使用read超时一例 先前有个编译…...

Windows环境安装nvm,并使用nvm管理nodejs版本教程

目录 1.nvm安装步骤 2.验证nvm是否安装成功 3.查看本地可以安装的所有版本 4.安装特定nodejs版本 5.配置nvm镜像 6.使用特定nodejs版本 7.给nodejs配置镜像和环境变量 8.查看本地安装的所有版本(* 表示当前版本) 9.卸载指定版本的nodejs 前端开发中&#xff0c;不…...

C++中常用的排序方法之——冒泡排序

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C中常用的排序方法之——冒泡排序的…...

SQL进阶实战技巧:如何分析浏览到下单各步骤转化率及流失用户数?

目录 0 问题描述 1 数据准备 2 问题分析 3 问题拓展 3.1 跳出率计算 3.2 计算从浏览商品到支付订单的不同路径的用户数&#xff0c;并按照用户数降序排列。 往期精彩 0 问题描述 统计从浏览商品到最终下单的各个步骤的用户数和流失用户数,并计算转化率 用户表结构和…...

NLP模型大对比:Transformer >Seq2Seq > LSTM > RNN > n-gram

结论 Transformer 大于 传统的Seq2Seq 大于 LSTM 大于 RNN 大于 传统的n-gram n-gram VS Transformer 我们可以用一个 图书馆查询 的类比来解释它们的差异&#xff1a; 一、核心差异对比 维度n-gram 模型Transformer工作方式固定窗口的"近视观察员"全局关联的&q…...

接口技术-第5次作业

目录 作业内容 解答 一、填空题 二、综合题 1.采用AD570通过82C55A与CPU接口&#xff0c;82C55A的端口地址为300H~303H,完成用查询方式采集250个数据&#xff0c;送到2000H开始的存储单元存储。绘制电路连接图&#xff08;AD570的4种主要信号线都要标出&#xff09;。 2…...

实战技巧:如何快速提高网站的收录比例?

本文转自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/28.html 快速提高网站的收录比例是网站优化中的重要目标之一。以下是一些实战技巧&#xff0c;可以帮助你实现这一目标&#xff1a; 一、内容优化 高质量原创内容&#xff1a; 确保网站内…...

WEB集群6-10天

第六天 nginx编译安装 全新的进行编译安装 [rootweb-1 ~]# mkdir /nginx [rootweb-1 ~]# cd /nginx/ [rootweb-1 nginx]# ls [rootweb-1 nginx]#curl -O https://nginx.org/download/nginx-1.26.1.tar.gz解压源码包 [rootweb-1 nginx]#tar xf nginx-1.26.1.tar.gz [rootw…...

10.共享内存 信号量集 消息队列

10.共享内存 信号量集 消息队列 **1. IPC对象操作通用框架****2. 共享内存&#xff08;Shared Memory&#xff09;****3. 信号量集&#xff08;Semaphore&#xff09;****4. 消息队列&#xff08;Message Queue&#xff09;****5. 练习与作业****6. 总结** 1. IPC对象操作通用框…...

玩转大语言模型——使用langchain和Ollama本地部署大语言模型

系列文章目录 玩转大语言模型——使用langchain和Ollama本地部署大语言模型 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 玩转大语言模型——使用GraphRAGOllama构建知识图谱 玩转大语言模型——完美解决Gra…...

数据结构与算法学习笔记----容斥原理

数据结构与算法学习笔记----容斥原理 author: 明月清了个风 first publish time: 2025.1.30 ps⭐️介绍了容斥原理的相关内容以及一道对应的应用例题。 Acwing 890. 能被整除的数 [原题链接](890. 能被整除的数 - AcWing题库) 给定一个整数 n n n和 m m m个不同的质数 p 1 …...

Appium介绍

在使用不同版本的Appium包进行自动化测试时&#xff0c;出现警告问题可能是由于版本不兼容、配置不正确等原因导致的。下面将详细介绍解决这些问题的步骤&#xff0c;确保模拟器能够正常启动&#xff0c;并能在Appium查看器中同步显示。 1. 环境准备 首先&#xff0c;确保你已…...

doris:Bitmap

BITMAP 类型可以在 Duplicate 表、Unique 表、Aggregate 表中使用&#xff0c;只能作为 Key 类&#xff0c;无法作为 Value 列使用。在 Aggregate 表中使用 BITMAP 类型&#xff0c;其建表时必须使用聚合类型 BITMAP_UNION。用户不需要指定长度和默认值。长度根据数据的聚合程度…...

gitee——报错修改本地密码

有时候当我们向远端push本地的仓库时会有一些报错的行为。 如下&#xff1a; 这是因为我们在gitee修改了密码时&#xff0c;本地还没有更新提交&#xff0c;总是报错 解决修改密码报错 如下&#xff1a; 1.在本地点击搜索栏找到控制面板 步骤如下...

Leetcode 45. 跳跃游戏 II

这题是一个动态规划问题&#xff0c;首先我先说一下自己的动态规划解题步骤&#xff1a; 1&#xff0c;首先需要明确动态规划数组的含义&#xff1a;这个是根据题目来定的&#xff0c;这一个题目的数组含义&#xff1a;dp【i】指的是从0跳到i所需要的最小的步骤。 2&#xff…...

ROS2---基础操作

工作空间(workspace) workspace是一个存放项目开发相关文件的文件夹。例如我们要开发一个机器人&#xff0c;我们可以创建一个工作空间&#xff0c;然后存放这个机器人不同功能的包&#xff08;感知&#xff08;雷达&#xff0c;相机等&#xff09;&#xff0c;运动&#xff0…...

【Leetcode 每日一题】350. 两个数组的交集 II

问题背景 给你两个整数数组 n u m s 1 nums_1 nums1​ 和 n u m s 2 nums_2 nums2​&#xff0c;请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数&#xff0c;应与元素在两个数组中都出现的次数一致&#xff08;如果出现次数不一致&#xff0c;则考虑取较小值…...

第13章 深入volatile关键字(Java高并发编程详解:多线程与系统设计)

1.并发编程的三个重要特性 并发编程有三个至关重要的特性&#xff0c;分别是原子性、有序性和可见性 1.1 原子性 所谓原子性是指在一次的操作或者多次操作中&#xff0c;要么所有的操作全部都得到了执行并 且不会受到任何因素的干扰而中断&#xff0c;要么所有的操作都不执行…...

STM32 PWMI模式测频率占空比

接线图&#xff1a; PWMI基本结构 代码配置&#xff1a; 与上一章输入捕获代码一样&#xff0c;根据结构体&#xff0c;需要在输入捕获单元再配置一个通道。我们调用一个函数 这个函数可以给结构体赋值&#xff0c;当我们定义了一遍结构体参数&#xff0c;再调用这个函数&…...

无心剑七绝《恭贺新春》

七绝恭贺新春 软件通灵万象真 生机繁茂绘星辰 智联世界情不尽 系统更新又一春 2025年1月29日 平水韵十一真平韵 无心剑七绝《恭贺新春》以“软件生态”为题旨&#xff0c;巧妙融入新春喜庆氛围&#xff0c;展现出科技与自然和谐共生的意境。首句“软件通灵万象真”&#xff0c;…...

低代码产品表单渲染架构

在React和Vue没有流行起来的时候&#xff0c;低代码产品的表单渲染设计通常会使用操作Dom的方式实现。 下面是一个表单的例子&#xff1a; 产品层 用户通过打开表单&#xff0c;使用不同业务场景业务下的表单页面&#xff0c;中间的Render层就是技术实现。 每一个不同业务的表单…...

allegro修改封闭图形线宽

说在前面 我们先把最优解说在前面,然后后面再说如果当时不熟悉软件的时候为了挖孔是用了shapes该怎么修改回来。 挖空最方便的方式是在cutout层画一个圆弧,下面开始图解,先add一个圆弧 z 最好是在画的时候就选择好层,如果忘记了后续再换回去也行,但好像软件有bug,此处并…...

C++实现2025刘谦魔术(勺子 筷子 杯子)

目录 1、魔术步骤 2、C代码 2.1、定义物品 2.2、枚举初始顺序 2.3、进行step2筷子交换 2.4、进行step3杯子交换 2.5、进行step4勺子交换 3、运行结果 4、全部源码 又是一年春晚啦&#xff0c;今年比较期待的是刘谦的魔术表演&#xff0c;现在用C实现刘谦的第一个魔术&…...

Leetcode:219

1&#xff0c;题目 2&#xff0c;思路 第一种就是简单的暴力比对当时过年没细想 第二种&#xff1a; 用Map的特性key唯一&#xff0c;把数组的值作为Map的key值我们每加载一个元素都会去判断这个元素在Map里面存在与否如果存在进行第二个判断条件abs(i-j)<k,条件 符合直接…...

SpringBoot+Vue的理解(含axios/ajax)-前后端交互前端篇

文章目录 引言SpringBootThymeleafVueSpringBootSpringBootVue&#xff08;前端&#xff09;axios/ajaxVue作用响应式动态绑定单页面应用SPA前端路由 前端路由URL和后端API URL的区别前端路由的数据从哪里来的 Vue和只用三件套axios区别 关于地址栏url和axios请求不一致VueJSPS…...

小米CR6606,CR6608,CR6609 启用SSH和刷入OpenWRT 23.05.5

闲鱼上收了一台CR6606和一台CR6609, 一直没时间研究, 趁春节假期把这两个都刷成 OpenWRT 配置说明 CPU: MT7621AT&#xff0c;双核880MHz内存: NT5CC128M16JR-EKI 或 M15T2G16128A, 256MB闪存: F59L1G81MB, 128MB无线基带芯片(BB): T7905DAN无线射频芯片(RF): MT7975DN无外置F…...

我的求职面经:(2)C++中空指针请使用nullptr不要使用NULL

1. C中NULL定义就是整数字面量0 2. 对于C函数&#xff0c;由于存在重载&#xff0c;使用NULL而不是nullptr可能导致函数走错重载。 3. C中定义NULL为&#xff08;void* &#xff09;0&#xff0c;确实是代表空指针。使用时隐式转换成对应的需要类型的空指针。 4. C中void指针…...

Java8_StreamAPI

Stream 1.创建流 1.1 集合创建流 List<String> list List.of("a", "b", "c"); Stream<String> stream list.stream(); stream.forEach(System.out::println);1.2 数组创建流 String[] array {"a","b",&qu…...

[STM32 - 野火] - - - 固件库学习笔记 - - -十二.基本定时器

一、定时器简介 STM32 中的定时器&#xff08;TIM&#xff0c;Timer&#xff09;是其最重要的外设之一&#xff0c;广泛用于时间管理、事件计数和控制等应用。 1.1 基本功能 定时功能&#xff1a;TIM定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中…...

信息学奥赛一本通 1606:【 例 1】任务安排 1 | 洛谷 P2365 任务安排

【题目链接】 ybt 1606&#xff1a;【 例 1】任务安排 1 洛谷 P2365 任务安排 【题目考点】 1. 动态规划&#xff1a;线性动规 【解题思路】 可以先了解法1&#xff0c;虽然不是正解&#xff0c;但该解法只使用了动规的基本思路&#xff0c;易于理解&#xff0c;有助于理解…...

【解决方案】MuMu模拟器移植系统进度条卡住98%无法打开

之前在Vmware虚拟机里配置了mumu模拟器&#xff0c;现在想要移植到宿主机中 1、虚拟机中的MuMu模拟器12-1是目标系统&#xff0c;对应的目录如下 C:\Program Files\Netease\MuMu Player 12\vms\MuMuPlayer-12.0-1 2、Vmware-虚拟机-设置-选项&#xff0c;启用共享文件夹 3、复…...