以报时机器人为例详细介绍tracker_store和event_broker

news2024/11/15 17:45:27

  报时机器人源码参考[1][2],本文重点介绍当 tracker_store 类型为 SQL 时,events 表的表结构以及数据是如何生成的。以及当 event_broker 类型为 SQL 时,events 表的表结构以及数据是如何生成的。

一.报时机器人启动 [3]

  Rasa 对话系统启动方式详见参考文献[3]中执行程序部分,这里不再赘述。如下所示:

1.加载模型:rasa run --cors "*"

2.运行 action server:rasa run actions

3.运行 Web 页面:python -m http.server 8080


二.(tracker_store)endpoints.yml 和 events 表结构

  使用 mysql 数据库来存储对话,使用 MySQL 新建 db 为 rasa_tracker_store,其中字符集和排序规则分别为 utf8mb4 – UTF-8 Unicode 和 utf8mb4_0900_ai_ci。

1.endpoints.yml 配置文件

tracker_store:
    type: SQL
    dialect: "mysql+pymysql"
    url: "localhost"  # your mysql host
    db: "rasa_tracker_store"  # name of the mysql database
    username: "root"  # username to access the database
    password: "root"  # password to access the database

2.新建数据库 rasa_tracker_store

3.events 表结构

(1)id:主键 id

(2)sender_id:发送者 id

(3)type_name:event 的类型名字

(4)timestamp:时间戳

(5)intent_name:意图名字

(6)action_name:action 名字

(7)data:数据

4.events 表数据内容

  以用户问:“今天星期几”,机器答:"星期三"为例子展开介绍。

  生成的 rasa_tracker_store.events 数据表内容,如下所示:

(1)id:主键 id。

  这个自增主键就不用多说了。

(2)sender_id:发送者 id。

  比如,oCMNVZ44YCbHIcFYAAAB。这个数据是如何来的?生成的规则是什么呢?

sender_id 是在 SQLTrackerStore 类中的 SQLEvent 子类中初始化的。SQLEvent 子类是 SQLAlchemy 的一部分,用于在数据库中创建一个表。在这个表中,sender_id 是一个字段,它的类型是字符串(最大长度为 255),并且它被设置为非空(nullable=False),并且为其创建了索引(index=True)。这意味着在数据库中,sender_id 字段不能为 null,并且可以被快速查找。

  sender_id 是在创建 DialogueStateTracker 对象时传入的一个参数,它通常用于标识对话的发送者。在 Rasa 中,每个对话都有一个唯一的 sender_id,这样可以区分不同的用户会话。在 from_events 类方法中,sender_id 是作为第一个参数传入的。这个方法用于从一系列事件中创建一个 DialogueStateTracker 对象。这些事件会被应用到新的跟踪器上,以重建其状态。生成 sender_id 的具体规则取决于你的应用,当客户端是 Rasa Shell、Rasa X、HTTP API 等的时候,都不相同。由于本次使用的是 Socket 方式,可以顺藤摸瓜去找 sender_id 的具体生成规则,这里不再细节展开。rasa/core/channels/socketio.py 如下所示:

(3)type_name:event 的类型名字。

  比如,action、session_started、user、slot、user_featurization、bot。这个数据是什么?除了这个数据还有其它的类型名字吗?(列出全部)。rasa/shared/core/events.py 如下所示:

序号事件类事件类型名字备注
1Event(ABC)类“event”描述对话中的事件以及它们如何影响对话状态。用户与助手进行对话期间发生的所有事情的不可变表示。告诉 rasa.shared.core.trackers.DialogueStateTracker 如何在事件发生时更新其状态。
2UserUttered(Event)“user”用户对机器人说了些什么。作为副作用,将在 Tracker 中创建一个新的 Turn
3DefinePrevUserUtteredFeaturization(SkipEventInMDStoryMixin)“user_featurization”存储 action 是基于文本还是意图预测的信息。
4EntitiesAdded(SkipEventInMDStoryMixin)“entities”用于将提取的实体添加到 tracker 状态的事件。
5BotUttered(SkipEventInMDStoryMixin)“bot”机器人对用户说了些什么。此类在故事训练中不使用,因为它包含在 ActionExecuted 类中。在 Tracker 中进行了记录。
6SlotSet(Event)“slot”用户已指定其对 slot 值的偏好。每个 slot 都有一个名称和一个值。此事件可用于在对话中设置 slot 的值。作为副作用,Tracker 的插槽将被更新,以便 tracker.slots[key]=value。
7Restarted(AlwaysEqualEventMixin)“restart”对话应该重新开始,历史记录被擦除。与删除所有事件不同,可以使用此事件来重置跟踪器状态(例如,忽略任何过去的用户消息并重置所有插槽)。
8UserUtteranceReverted(AlwaysEqualEventMixin)“rewind”机器人会撤消最近的用户消息之前的所有内容。机器人将撤消最新的 UserUttered 之后的所有事件,这也意味着跟踪器上的最后一个事件通常是 action_listen,机器人正在等待新的用户消息。
9AllSlotsReset(AlwaysEqualEventMixin)“reset_slots”所有插槽都重置为其初始值。如果要保留对话历史记录并仅重置插槽,则可以使用此事件将所有插槽设置为其初始值。
10ReminderScheduled(Event)“reminder”在给定时间安排异步触发用户意图。如果需要,触发的意图可以包括实体。
11ReminderCancelled(Event)“cancel_reminder”取消某些工作。
12ActionReverted(AlwaysEqualEventMixin)“undo”机器人撤消了最后的操作。机器人会撤消最近的操作之前的所有内容。这包括操作本身以及操作创建的任何事件,例如设置插槽事件-机器人现在将使用最近操作之前的状态来预测新操作。
13StoryExported(Event)“export”故事应该转储到文件。
14FollowupAction(Event)“followup”排队后续操作。
15ConversationPaused(AlwaysEqualEventMixin)“pause”忽略用户的消息,让人类接管。作为副作用,Tracker 的 paused 属性将被设置为 True
16ConversationResumed(AlwaysEqualEventMixin)“resume”机器人接管对话。PauseConversation 的反义词。作为副作用,Tracker 的 paused 属性将被设置为 False
17ActionExecuted(Event)“action”操作描述了执行的操作 + 其结果。它包括一个操作和一个事件列表。操作将附加到 Tracker.turns 中的最新 Turn
18AgentUttered(SkipEventInMDStoryMixin)“agent”agent 对用户说了些什么。由于它包含在 ActionExecuted 类中,因此此类在故事训练中不使用。在 Tracker 中进行了条目。
19ActiveLoop(Event)“active_loop”如果给出了 name:使用 name 激活循环,否则停用活动循环。
20LegacyForm(ActiveLoop)“form”Form 事件的旧版处理程序。ActiveLoop 事件曾被称为 Form。这个类是为了处理旧的遗留事件,这些事件是使用旧的类型名称 form 存储的。
21LoopInterrupted(SkipEventInMDStoryMixin)“loop_interrupted”FormPolicy 和 RulePolicy 添加的事件。通知表单操作是否验证用户输入。
22LegacyFormValidation(LoopInterrupted)“form_validation”FormValidation 事件的旧版处理程序。LoopInterrupted 事件曾被称为 FormValidation。这个类是为了处理旧的遗留事件,这些事件是使用旧的类型名称 form_validation 存储的。
23ActionExecutionRejected(SkipEventInMDStoryMixin)“action_execution_rejected”通知 Core 操作的执行已被拒绝。
24SessionStarted(AlwaysEqualEventMixin)“session_started”标记新会话会话的开始。

(4)timestamp:Unix 时间戳。

  比如,1704300000,转换后的日期时间:2024-01-03 16:40:00。Unix 时间戳是指从 1970 年 1 月 1 日 00:00:00UTC(协调世界时)开始的秒数。

from datetime import datetime

timestamp = 1704300000
date_object = datetime.utcfromtimestamp(timestamp)

print("转换后的日期时间:", date_object)

(5)intent_name:意图名字

  比如,query_weekday。报时机器人总共的意图包括 greet、goodbye、query_time、query_date、query_weekday。对应的例子如下所示:

version: "3.0"
nlu:
  - intent: greet
    examples: |
      - 你好
      - 您好
      - hello
      - hi
      - 喂
      - 在么
  - intent: goodbye
    examples: |
      - 拜拜
      - 再见
      - 拜
      - 退出
      - 结束
  - intent: query_time
    examples: |
      - 现在几点了
      - 什么时候了
      - 几点了
      - 现在什么时候了
      - 现在的时间
  - intent: query_date
    examples: |
      - [今天](date)几号
      - [今天](date)是几号
      - [昨天](date)几号
      - [明天](date)几号
      - [今天](date)的日期
      - [今天](date)几号了
      - [明天](date)的日期
      - 几号
  - intent: query_weekday
    examples: |
      - [今天](date)星期几
      - [明天](date)星期几
      - [昨天](date)星期几
      - [今天](date)是星期几
      - 星期几

(6)action_name:action 名字

  比如,action_session_start(会话开始)、action_listen(机器人处于监听状态,机器人每次回答完毕后都会处于监听状态)、date(日期实体)、action_query_weekday(自定义 action)。除此之外,还有哪些 action_name 呢?(列出全部)。rasa/core/actions/action.py 如下所示:

序号动作类动作名字备注
1ActionNotImplementedError响应对话状态的下一个操作。
2ActionBotResponse(Action)——一个动作,其唯一效果是在运行时发出响应。
3ActionEndToEndResponse(Action)——动作以端到端响应向用户发出响应。
4ActionRetrieveResponse(ActionBotResponse)——查询响应选择器以获取适当的响应的操作。
5ActionBack(ActionBotResponse)“action_back”将跟踪器状态恢复两个用户话语。
6ActionListen(Action)“action_listen”任何回合中的第一个动作-机器人等待用户消息。机器人应停止采取进一步的操作,并等待用户说些什么。
7ActionRestart(ActionBotResponse)“action_restart”将跟踪器重置为其初始状态。如果可用,则发出重启响应。
8ActionSessionStart(Action)“action_session_start”应用一个对话会话开始,将上一个会话中的所有 SlotSet 事件应用于新会话。
9ActionDefaultFallback(ActionBotResponse)“action_default_fallback”执行回退操作并返回对话的上一个状态。
10ActionDeactivateLoop(Action)“action_deactivate_loop”停用活动循环。
11RemoteAction(Action)————
12ActionRevertFallbackEvents(Action)“action_revert_fallback_events”撤消 TwoStageFallbackPolicy 期间完成的事件。这将撤消在 TwoStageFallbackPolicy 的回退期间完成的用户消息和机器人话语。通过这样做,不需要为不同的路径编写自定义故事,而只需要编写快乐的路径。这已被弃用,一旦删除 TwoStageFallbackPolicy,就可以删除它。
13ActionUnlikelyIntent(Action)“action_unlikely_intent”一个动作,指示 NLU 预测的意图是意外的。此操作可以由 UnexpecTEDIntentPolicy 预测。
14ActionDefaultAskAffirmation(Action)“action_default_ask_affirmation”默认实现,询问用户确认他的意图。建议使用自定义操作覆盖此默认操作,以获得更有意义的确认提示。例如。具有意图的描述而不是其标识符名称。
15ActionDefaultAskRephrase(ActionBotResponse)“action_default_ask_rephrase”默认实现,询问用户重新表达他的意图。
16ActionSendText(Action)“action_send_text”向输出通道发送文本消息。
17ActionExtractSlots(Action)“action_extract_slots”每个用户回合后自动运行的默认操作。在下一个预测的操作运行之前,在 MessageProcessor.handle_message(…)中自动执行操作。根据分配的槽映射将插槽设置为从用户消息中提取的值。
18ACTION_TWO_STAGE_FALLBACK_NAME“action_two_stage_fallback”——
19ACTION_VALIDATE_SLOT_MAPPINGS“action_validate_slot_mappings”——
20RULE_SNIPPET_ACTION_NAME“…”——

(7)data:数据

  取出一条 data 数据字段进行 json 显示,如下所示:

{
        "event": "action",
        "timestamp": 1704297163.3703225,
        "metadata": {
                "model_id": "4ca8c86f1301497f9488c47c860f39fd",
                "assistant_id": "20240103-232935-excited-category"
        },
        "name": "action_session_start",
        "policy": null,
        "confidence": 1.0,
        "action_text": null,
        "hide_rule_turn": false
}
  • event:事件的名字。(列出全部)
  • timestamp:时间戳。
  • metadata-model_id:模型 id。这个并不是模型的名字,比如训练的报时机器人模型为 20240103-233232-windy-borzoi.tar.gz
  • metadata-assistant_id:这个是 config.yml 文件中定义的 assistant_id: 20240103-232935-excited-category
  • name:action 的名字。
  • policy:使用的策略。
  • confidence:置信度。
  • action_text:动作文本,即端到端机器人响应的文本。
  • hide_rule_turn:是否隐藏规则回合。

  上述字段大都来自于 ACTION_EXECUTED(rasa/shared/utils/schemas/events.py),ACTION_EXECUTED 是一个字典,它定义了 Rasa 中 “action” 事件的 JSON schema。这个 schema 描述了 “action” 事件的数据结构,包括它的属性和这些属性的类型。如下所示:

ACTION_EXECUTED = {
    "properties": {
        "event": {"const": "action"},
        "policy": {"type": ["string", "null"]},
        "confidence": {"type": ["number", "null"]},
        "name": {"type": ["string", "null"]},
        "hide_rule_turn": {"type": "boolean"},
        "action_text": {"type": ["string", "null"]},
    }
}

  在 ACTION_EXECUTED schema 中,相关属性解释如下所示:

  • event: 这是一个常量,值为 “action”,表示这是一个 “action” 事件。
  • policy: 这是一个字符串,表示执行这个动作的策略的名称。它也可以为 null。
  • confidence: 这是一个数字,表示执行这个动作的策略的置信度。它也可以为 null。
  • name: 这是一个字符串,表示执行的动作的名称。它也可以为 null。
  • hide_rule_turn: 这是一个布尔值,表示是否隐藏规则回合。
  • action_text: 这是一个字符串,表示动作的文本。它也可以为 null。

  这个 schema 用于验证 “action” 事件的数据是否符合预期的格式。如果一个 “action” 事件的数据不符合这个 schema,那么在处理这个事件时,Rasa 将会抛出一个错误。

5.action 和 event 间的关系

  在 Rasa 中,动作(action)和事件(event)是两个不同但相关的概念。如下所示:

(1)action

  动作是在对话中执行的一些操作,例如向用户发送消息、调用外部服务、或者进行自定义的计算。在 Rasa 中,动作通常与对话策略相关联,用于决定在特定的对话状态下应该执行哪个动作。动作由自定义的动作类或内置的动作类实现,它们被定义为继承自 Action 类。

(2)event

  事件是对话中的状态更改的表示,例如用户的输入、机器人的响应、槽位的更新等。在 Rasa 中,对话的历史记录是一系列事件的集合。事件被用于跟踪对话的状态,对话管理器使用事件来更新对话状态。不同的事件类型表示不同的对话动作和状态变化。

(3)两者关系

  • 当动作执行时,通常会生成一个或多个事件,这些事件描述了对话状态的变化。
  • 每个对话轮次中都会有一系列事件,包括用户的输入事件(例如 UserUttered)、动作执行事件(例如 ActionExecuted)、槽位更新事件(例如 SlotSet)、机器人响应事件(例如 BotUttered)等。

  在对话中,动作和事件密切相互关联。动作执行时会触发事件,这些事件进而影响对话状态的演进。一般来说,对话的历史记录中的事件序列描述了对话的全貌,对话管理器利用这些事件来进行决策。

三.(event_broker)endpoints.yml 和 events 表结构

1.endpoints.yml 配置文件

  使用 mysql 数据库来消息队列,如下所示:

event_broker:
  type: SQL
  url: "localhost"
  port: 3306
  dialect: "mysql+pymysql"
  username: "root"
  password: "root"
  db: "rasa_event_broker"

2.新建数据库 rasa_tracker_store

  创建数据库方式与 rasa_tracker_store 相同,这里不再赘述。

3.events 表结构

  生成的 rasa_event_broker.events 数据表内容,如下所示:

(1)id:主键 id

(2)sender_id:发送者 id

(3)data:数据

4.events 表数据内容

  取出一条 data 数据字段进行 json 显示,如下所示:

{
        "sender_id": "oCMNVZ44YCbHIcFYAAAB",
        "event": "action",
        "timestamp": 1704297163.3703225,
        "metadata": {
                "model_id": "4ca8c86f1301497f9488c47c860f39fd",
                "assistant_id": "20240103-232935-excited-category"
        },
        "name": "action_session_start",
        "policy": null,
        "confidence": 1.0,
        "action_text": null,
        "hide_rule_turn": false
}

  发现 event_broker.events.data 和 tracker_store.events.data 相比,除了多一个 sender_id 字段,其它的都是一样的。跟踪源码发现,如下所示:

  执行顺序是先发布新的 tracker 事件集合到 event_broker,然后逐一遍历 event,并将其存储到 tracker_store.event 表中。

四.EventBroker 类和 SQLEventBroker(EventBroker)类

1.EventBroker 类

2.SQLEventBroker(EventBroker)类

  SQLEventBroker(EventBroker)类有个内部类 SQLBrokerEvent(Base),定义了 events 的 3 个字段,分别为 id、sender_id 和 data。剩下的基本是对 EventBroker 基类中方法的具体实现。rasa/core/brokers/sql.py 如下所示:



五.TrackerStore 类和 SQLTrackerStore 类

1.TrackerStore 类

  表示所有 TrackerStore 的公共行为和接口,如下所示:

2.SQLTrackerStore 类

  对 TrackerStore 基类的实现,包括 InMemoryTrackerStore、RedisTrackerStore、DynamoTrackerStore、MongoTrackerStore、SQLTrackerStore。SQLTrackerStore(TrackerStore, SerializedTrackerAsText)类有个内部类 SQLEvent(Base),定义了 events 的 7 个字段,分别为 id、sender_id、type_name、timestamp、intent_name、action_name 和 data。剩下的基本是对 TrackerStore 基类中方法的具体实现。rasa/core/tracker_store.py 如下所示:



参考文献

[1] rasa-v2024010701(报时机器人)源码:https://github.com/ai408/nlp-engineering/tree/main/知识工程-对话系统/公众号代码/rasa-v2024010701

[2] 报时机器人的 rasa shell 执行流程分析:https://z0yrmerhgi8.feishu.cn/wiki/CvASwk5SmiYkCXkqONycSxVfnJg

[3] 打通 Rasa Action Server 和 LLM 接口的尝试方法:https://z0yrmerhgi8.feishu.cn/wiki/UQa0wQBeJi6K7oknz2wcaSTnnNb

[4] 以报时机器人为例详细介绍tracker_store和event_broker:https://z0yrmerhgi8.feishu.cn/wiki/SQSGwzYR7iKSNukQDKicz1Vqnvg

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

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

相关文章

基于springboot+vue心理测试管理系统

摘要 基于Spring Boot 和 Vue 的心理测试管理系统是一个综合利用现代Web开发技术的应用程序。系统采用了Spring Boot作为后端框架,通过其简化的配置和强大的功能提供了稳健的服务器端支持。前端则使用Vue.js,一个灵活、高效的JavaScript框架,…

通义千问AI挑战赛赛后反思

个人理解: 初赛阶段主要聚焦在如何通过 SFT 提升基础模型的代码能力,需要选手基于最新开源的 Qwen 1.8 模型作为基础模型,上分的关键主要通过收集高质量的代码数据提升模型的在Python, JavaScript, Java, Go, C, Rust六种编程语言的代码生成…

档案数字化怎样快速整理资料

对于机构和组织来说,档案数字化是一个重要的信息管理和保护措施。要快速整理资料进行档案数字化,可以遵循以下步骤: 1. 准备工具和设备:确保有一台计算机、扫描仪和相关软件。 2. 分类和组织资料:先将资料分类&#xf…

c++最值查找

目录 min和max函数 min_element和max_element 例 nth_element函数 例 例题 题目描述 输入描述 输出描述 解 min和max函数 只能传入两个值或一个列表 时间复杂度为O(1),数组O(n),n为元素个数 min_element和max_element min_element(st,ed)返回地址[st,…

数据结构学习之顺序栈应用的案例(有效的括号)

实例要求: 给定一个只包括 (,),{,},[,] 的字符串 s ,判断字符串是否有效; 有效字符串需满足的条件: 1、左括号必须用相同类型的右括号闭合; 2、左括号必须…

服务端性能测试——性能测试工具JMeter-L1

第一遍没学懂,后续文章会更新~ 目录: 1.JMeter介绍与安装Meter简介JMeter安装2.JMeter的运行JMeter运行、界面功能简介3.使用代理服务器录制请求录制压测脚本(一)Web端脚本录制方法4.测试计划5.线程组6.控制器7.JMeter采样器/取…

Postman接口测试工具最全实用教程

一、postman简介 1、postman的特点 postman只做http协议的接口的测试,是一种最广泛REST接口测试客户端软件。postman支持http协议的所有请求方式,包括get、post、head、put、delete等。postman支持各种额外的头部字段的添加。postman除了可以模拟普通表…

chat-plus部署指南

目录 1.下载代码 2.启动 3.测试 1.下载代码 cd /optwget https://github.com/yangjian102621/chatgpt-plus/archive/refs/tags/v3.2.4.1.tar.gz 2.启动 cd /opt/chatgpt-plus-3.2.4.1/deploydocker-compose up -d 3.测试 管理员地址xxx:8080/admin 账号密码admin/admin1…

java流程控制-给个一件三连呗!✨✨✨✨✨

接下来我们来看流程控制方面的知识 文章目录 1.Scanner类的使用1.1 使用next()进行接收1.2 nextLine()1.3 hasNext()1.4 scanner.nextInt() 2.选择结构2.1 if...else....语句2.2 if....else if....else...语句2.3 switch() case...语句 3.循环结构3.1for 循环:3.2w…

ES索引原理

ES在检索时底层使用的就是倒排索引,正向索引是通过key找value,反向索引则是通过value找key。 索引会分为两个区域:索引区和元数据区。数据是这样存储在里面的: 简单理解就是:当要录入一条数据时,首先会将完…

Linux之Iptables简易应用

文档形成时期:2009-2024年 和iptables打交道有15年了,经过无数实践后,形成一个简易应用文档。 文档主题是简易应用,所以其原理不详述了。 因软件世界之复杂和个人能力之限,难免疏漏和错误,欢迎指正。 文章目…

伴随矩阵定义和计算

一、伴随矩阵定义 1)代数余子式 代数余子式也很好理解,在余子式的基础上多了一个-1的次方而已。 2)余子式 余子式很好理解,就是除了这个元素,出去该行该列剩下的行列式的值。 求每个元素的代数余子式,按行求&#xf…

关于白盒测试,这些技巧你得游刃有余~

对于很多刚开始学习软件测试的小伙伴来说,如果能尽早将黑盒、白盒测试弄明白,掌握两种测试的结论和基本原理,将对自己后期的学习有较好的帮助。今天,我们就来聊聊黑盒、白盒测试的相关话题。 1、黑盒测试的方法和小结 最常见黑盒…

【C++】:C++中的STL序列式容器vector源码剖析

⛅️一 vector概述 vector的使用语法可以参考文章:​ 总的来说:vector是可变大小数组 特点: 支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢 元素保存在连续的内存空间中,因此通过下标取值非常快 在容器中间位置添加…

SpringIOC之support模块GenericApplicationContext

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌ 博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+…

【Spring 篇】基于注解的Spring事务控制详解

嗨,亲爱的读者朋友们!欢迎来到这篇关于基于注解的Spring事务控制的博客。如果你曾为事务处理而头痛,那么这里将为你揭开事务的神秘面纱。我们将一步步深入探讨Spring事务的世界,用简单易懂的语言、充满情感色彩的文字,…

fastadmin 框架如何移除图片上传后预览中的删除按钮

在FastAdmin中,当我们启用了图片上传预览时,在预览区域会自动生成预览图和删除按钮,如下图: 如果我们想上移除掉这里的删除按钮,则需要启用自定义预览模板的功能。 首先我们找到视图中我们的预览容器,比如…

C++内存管理机制(侯捷)笔记4(完结)

C内存管理机制(侯捷) 本文是学习笔记,仅供个人学习使用。如有侵权,请联系删除。 参考链接 Youtube: 侯捷-C内存管理机制 Github课程视频、PPT和源代码: https://github.com/ZachL1/Bilibili-plus 介绍 下面是第四讲和第五讲…

STM32F103RCT6开发板M3单片机教程07-TIMER1CH1输出 PWM做LED呼吸灯

概述 本教程使用是(光明谷SUN_STM32mini开发板) 免费开发板 在谷动谷力社区注册用户,打卡,发帖求助都可以获取积分,当然最主要是发原创应用文档奖励更多积分. (可用积分换取,真的不用钱&…

Mysql InnoDB行锁深入理解

Record Lock记录锁 Record Lock 称为记录锁,锁住的是一条记录。而且记录锁是有 S 锁和 X 锁之分的: 当一个事务对一条记录加了 S 型记录锁后,其他事务也可以继续对该记录加 S 型记录锁(S 型与 S 锁兼容),…