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

鸿蒙进阶——驱动框架UHDF 机制核心源码解读(一)

文章大纲

  • 引言
  • 一、uhdf 概述
  • 二、uhdf 的核心参与角色
    • 1、drivers/hdf_core/adapter/uhdf2/manager/device_manager.c
      • 1.1、drivers/hdf_core/framework/core/manager/src/devmgr_service.c#DevmgrServiceGetInstance通过objectId获取IDevmgrService实例
      • 1.2、drivers/hdf_core/framework/core/shared/src/hdf_object_manager.c#HdfObjectManagerGetObject——>HdfObjectManagerGetCreators
    • 2、drivers/hdf_core/adapter/uhdf2/host/devhost.c、driver_loader_full.c和device_info.hcs
  • 三、hdf_device_manager的启动
    • 1、DevmgrServiceGetInstance()
    • 2、IDevmgrService#StartService(instance)——>drivers/hdf_core/framework/core/manager/src/devmgr_service.c#DevmgrServiceStartService
      • 2.1、DevSvcManagerStartService()
      • 2.2、DevmgrServiceStartDeviceHosts

引言

前面两篇文章从理论的角度简单介绍了下HDF驱动框架的基本理论知识和原理,接下来就从源码角度介绍下UHDF核心工作流程。

一、uhdf 概述

区别于传统的硬件驱动khdf,OpenHarmony还设计了一层uhdf,本质上就是一个应用进程,主要是面向用户层提供与驱动的交互接口层。与khdf一样每一个uhdf 都需要注册到device_info.hcs文件内,当然了uhdf 正常工作时是离不开khdf的。

二、uhdf 的核心参与角色

NNRT HOST 的启动也是由uhdf 驱动的,以下是uhdf工作流程

1、drivers/hdf_core/adapter/uhdf2/manager/device_manager.c

device_manager.c承担着所有硬件外设的管理角色,所有设备的host_service服务都由它统一管理,再由devhost.c创建对应的xxx_host_service需要主动注册到device_manager中,当需要使用时直接通过device_manager获取并使用。

int main()
{HDF_LOGI("start hdf device manager");int status = HDF_FAILURE;struct IDevmgrService* instance = DevmgrServiceGetInstance();if (instance->StartService != NULL) {status = instance->StartService(instance);}(void)DevMgrUeventReceiveStart();DevMgrRegisterDumpFunc();if (status == HDF_SUCCESS) {struct DevmgrServiceFull *fullService = (struct DevmgrServiceFull *)instance;struct HdfMessageLooper *looper = &fullService->looper;if ((looper != NULL) && (looper->Start != NULL)) {looper->Start(looper);}}HDF_LOGE("starting device manager service failed, status is %{public}d", status);return status;
}

1.1、drivers/hdf_core/framework/core/manager/src/devmgr_service.c#DevmgrServiceGetInstance通过objectId获取IDevmgrService实例

struct IDevmgrService *DevmgrServiceGetInstance(void)
{static struct IDevmgrService *instance = NULL;if (instance == NULL) {instance = (struct IDevmgrService *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVMGR_SERVICE);}return instance;
}

1.2、drivers/hdf_core/framework/core/shared/src/hdf_object_manager.c#HdfObjectManagerGetObject——>HdfObjectManagerGetCreators

不同的Service 有各自对应的HdfObjectManagerGetCreators 实现。

2、drivers/hdf_core/adapter/uhdf2/host/devhost.c、driver_loader_full.c和device_info.hcs

.hcs是开发者注册hdf驱动列表的配置文件,再编译后会结合SeLinux 策略重新编译整理成.hcg文件,同时devhost.c 成为一个可执行文件,当需要拉起对应的uhdf _host_service时被执行,所以有可能被执行多次,而需要注意的是dev_host相当于是只是一个空壳,还需要driver_loader_full.c 来把真正这个uhdf 驱动的真正的业务逻辑对应的so 加载进来,才能成为一个真正的uhdf 设备驱动并且将其句柄缓存至系统的设备驱动列表中。以nnrt_host为例,当我们把nnrt_host 的uhdf驱动的信息添加到.hcs驱动列表文件后,当系统遍历时就会去执行devhost.c的main函数解析.hcg的信息,创建对应的nnrt_host的实例句柄并且加载其相应的so,再把符号连接到对应的位置,拉起对应的进程。

NNRT HOST 启动三部曲在这里插入图片描述

三、hdf_device_manager的启动

系统启动过程中首先是由脚本触发device_manager#main函数执行

int main()
{HDF_LOGI("start hdf device manager");int status = HDF_FAILURE;struct IDevmgrService* instance = DevmgrServiceGetInstance();...if (instance->StartService != NULL) {status = instance->StartService(instance);}(void)DevMgrUeventReceiveStart();DevMgrRegisterDumpFunc();if (status == HDF_SUCCESS) {struct DevmgrServiceFull *fullService = (struct DevmgrServiceFull *)instance;struct HdfMessageLooper *looper = &fullService->looper;if ((looper != NULL) && (looper->Start != NULL)) {looper->Start(looper);}}...return status;
}

1、DevmgrServiceGetInstance()

通过传入HDF_OBJECT_ID_DEVMGR_SERVICE作为objectId 获取IDevmgrService 的指针。

drivers/hdf_core/framework/core/manager/src/devmgr_service.c
struct IDevmgrService *DevmgrServiceGetInstance(void)
{static struct IDevmgrService *instance = NULL;if (instance == NULL) {instance = (struct IDevmgrService *)HdfObjectManagerGetObject(HDF_OBJECT_ID_DEVMGR_SERVICE);}return instance;
}

然后drivers/hdf_core/framework/core/shared/src/hdf_object_manager.c#HdfObjectManagerGetObject 里触发Create函数指针

struct HdfObject *HdfObjectManagerGetObject(int objectId)
{struct HdfObject *object = NULL;const struct HdfObjectCreator *targetCreator = HdfObjectManagerGetCreators(objectId);if ((targetCreator != NULL) && (targetCreator->Create != NULL)) {// 触发函数指针Create 执行object = targetCreator->Create();if (object != NULL) {object->objectId = objectId;}}return object;
}

在drivers/hdf_core/framework/core/common/src/devlite_object_config.c里定义了一个常量结构体,可以根据objectId拿到对应的成员变量并执行其Create指针指向的函数

const struct HdfObjectCreator *HdfObjectManagerGetCreators(int objectId)
{int numConfigs = sizeof(g_liteObjectCreators) / sizeof(g_liteObjectCreators[0]);if ((objectId >= 0) && (objectId < numConfigs)) {return &g_liteObjectCreators[objectId];}return NULL;
}static const struct HdfObjectCreator g_liteObjectCreators[] = {[HDF_OBJECT_ID_DEVMGR_SERVICE] ={.Create = DevmgrServiceCreate,.Release = DevmgrServiceRelease,},[HDF_OBJECT_ID_DEVSVC_MANAGER] ={.Create = DevSvcManagerExtCreate,.Release = DevSvcManagerExtRelease,},[HDF_OBJECT_ID_DEVHOST_SERVICE] ={.Create = DevHostServiceCreate,.Release = DevHostServiceRelease,},[HDF_OBJECT_ID_DRIVER_INSTALLER] ={.Create = DriverInstallerCreate,.Release = NULL,},[HDF_OBJECT_ID_DRIVER_LOADER] ={.Create = HdfDriverLoaderCreate,.Release = NULL,},[HDF_OBJECT_ID_DEVICE] ={.Create = HdfDeviceCreate,.Release = HdfDeviceRelease,},[HDF_OBJECT_ID_DEVICE_TOKEN] ={.Create = HdfDeviceTokenCreate,.Release = HdfDeviceTokenRelease,},[HDF_OBJECT_ID_DEVICE_SERVICE] ={.Create = DeviceNodeExtCreate,.Release = DeviceNodeExtRelease,}
};

触发函数指针Create 即执行DevmgrServiceCreate 给IDevmgrService结构体指针函数赋值后再返回。

bool DevmgrServiceConstruct(struct DevmgrService *inst)
{struct IDevmgrService *devMgrSvcIf = NULL;...devMgrSvcIf = (struct IDevmgrService *)inst;if (devMgrSvcIf != NULL) {devMgrSvcIf->AttachDevice = DevmgrServiceAttachDevice;devMgrSvcIf->DetachDevice = DevmgrServiceDetachDevice;devMgrSvcIf->LoadDevice = DevmgrServiceLoadDevice;devMgrSvcIf->UnloadDevice = DevmgrServiceUnloadDevice;devMgrSvcIf->AttachDeviceHost = DevmgrServiceAttachDeviceHost;devMgrSvcIf->StartService = DevmgrServiceStartService;devMgrSvcIf->PowerStateChange = DevmgrServicePowerStateChange;devMgrSvcIf->ListAllDevice = DevmgrServiceListAllDevice;DListHeadInit(&inst->hosts);return true;} else {return false;}
}

2、IDevmgrService#StartService(instance)——>drivers/hdf_core/framework/core/manager/src/devmgr_service.c#DevmgrServiceStartService

int DevmgrServiceStartService(struct IDevmgrService *inst)
{int ret;struct DevmgrService *dmService = (struct DevmgrService *)inst;...ret = DevSvcManagerStartService();HDF_LOGI("start svcmgr result %{public}d", ret);return DevmgrServiceStartDeviceHosts(dmService);
}

2.1、DevSvcManagerStartService()

DevSvcManagerGetInstance——>HdfObjectManagerGetObject——>HdfObjectManagerGetCreators——>根据objectId去HdfObjectCreator数组中去获取对应的指针,并触发Create函数指针

drivers/hdf_core/framework/core/manager/src/devmgr_service.c

int DevSvcManagerStartService(void)
{int ret;struct IDevSvcManager *svcmgr = DevSvcManagerGetInstance();if (svcmgr->StartService == NULL) {return HDF_SUCCESS;}//触发DevSvcManagerStubStartret = svcmgr->StartService(svcmgr);if (ret != HDF_SUCCESS) {HDF_LOGE("failed to start service manager");}return ret;
}

和上面类似先是执行Create 函数指针即DevSvcManagerStubCreate,并给StartService函数指针赋值

struct HdfObject *DevSvcManagerStubCreate(void)
{static struct DevSvcManagerStub *instance;instance = OsalMemCalloc(sizeof(struct DevSvcManagerStub));if (!DevSvcManagerStubConstruct(instance)) {OsalMemFree(instance);instance = NULL;}return (struct HdfObject *)instance;
}
static bool DevSvcManagerStubConstruct(struct DevSvcManagerStub *inst)
{...//给IDevSvcManager 的函数指针赋值if (!DevSvcManagerConstruct(&inst->super)) {HDF_LOGE("failed to construct device service manager");return false;}inst->super.super.StartService = DevSvcManagerStubStart;OsalMutexInit(&inst->devSvcStubMutex);HdfSListInit(&inst->devObjHolderList);return true;
}执行了上面后IDevSvcManager的函数指针StartService被赋值为DevSvcManagerStubStart并随即执行,用于注册到HDF和IPC相关的。
●HdfRemoteDispatcher 的Dispatch 函数指针被赋值为DevSvcManagerStubDispatch
●给DevSvcManagerStub的remote 对象赋值为远端代理对象以及监听远端代理对象死亡时间
●执行注册
drivers/hdf_core/adapter/uhdf2/manager/src/devsvc_manager_stub.c
int DevSvcManagerStubStart(struct IDevSvcManager *svcmgr)
{struct DevSvcManagerStub *inst = (struct DevSvcManagerStub *)svcmgr;...ServStatListenerHolderinit();...//后面IPC时会用到static struct HdfRemoteDispatcher dispatcher = {.Dispatch = DevSvcManagerStubDispatch};inst->remote = HdfRemoteServiceObtain((struct HdfObject *)inst, &dispatcher);if (inst->remote == NULL) {HDF_LOGE("failed to obtain device service manager remote service");return HDF_ERR_MALLOC_FAIL;}if (!HdfRemoteServiceSetInterfaceDesc(inst->remote, "HDI.IServiceManager.V1_0")) {HDF_LOGE("%{public}s: failed to init interface desc", __func__);HdfRemoteServiceRecycle(inst->remote);return HDF_ERR_INVALID_OBJECT;}inst->recipient.OnRemoteDied = DevSvcManagerOnServiceDied;//注册并发布int ret = HdfRemoteServiceRegister(DEVICE_SERVICE_MANAGER_SA_ID, inst->remote);if (ret != 0) {HDF_LOGE("failed to publish device service manager, %{public}d", ret);HdfRemoteServiceRecycle(inst->remote);inst->remote = NULL;} else {HDF_LOGI("publish device service manager success");inst->started = true;}return ret;
}

执行注册
drivers/hdf_core/adapter/uhdf2/ipc/src/hdf_remote_service.c

int HdfRemoteServiceRegister(int32_t serviceId, struct HdfRemoteService *service)
{return HdfRemoteAdapterAddSa(serviceId, service);
}int HdfRemoteAdapterAddSa(int32_t saId, struct HdfRemoteService *service)
{...auto saManager = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();const int32_t waitTimes = 50;const int32_t sleepInterval = 20000;int32_t timeout = waitTimes;while (saManager == nullptr && (timeout > 0)) {HDF_LOGI("waiting for samgr...");usleep(sleepInterval);saManager = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();timeout--;}struct HdfRemoteServiceHolder *holder = reinterpret_cast<struct HdfRemoteServiceHolder *>(service);int ret = saManager->AddSystemAbility(saId, holder->remote_);(void)OHOS::IPCSkeleton::GetInstance().SetMaxWorkThreadNum(g_remoteThreadMax++);HDF_LOGI("add sa %{public}d, ret = %{public}s", saId, (ret == 0) ? "succ" : "fail");...return HDF_SUCCESS;
}

原来注册、发布的对象都是SA,接下来就是SA相关的管理逻辑了。

2.2、DevmgrServiceStartDeviceHosts

static int DevmgrServiceStartDeviceHosts(struct DevmgrService *inst)
{int ret;struct HdfSList hostList;struct HdfSListIterator it;struct HdfHostInfo *hostAttr = NULL;HdfSListInit(&hostList);if (!HdfAttributeManagerGetHostList(&hostList)) {HDF_LOGW("%s: host list is null", __func__);return HDF_SUCCESS;}HdfSListIteratorInit(&it, &hostList);while (HdfSListIteratorHasNext(&it)) {hostAttr = (struct HdfHostInfo *)HdfSListIteratorNext(&it);ret = DevmgrServiceStartDeviceHost(inst, hostAttr);if (ret != HDF_SUCCESS) {HDF_LOGW("%{public}s failed to start device host, host id is %{public}u, host name is '%{public}s'",__func__, hostAttr->hostId, hostAttr->hostName);}}HdfSListFlush(&hostList, HdfHostInfoDelete);return HDF_SUCCESS;
}

然后DevmgrServiceStartHostProcess 里通过IDriverInstaller 启动StartDeviceHost,即执行DriverInstallerFullStartDeviceHost

static int DevmgrServiceStartHostProcess(struct DevHostServiceClnt *hostClnt, bool sync, bool dynamic)
{HDF_LOGE("NNRT#DevmgrServiceStartHostProcess ");int waitCount = WAIT_HOST_SLEEP_CNT;struct IDriverInstaller *installer = DriverInstallerGetInstance();if (installer == NULL || installer->StartDeviceHost == NULL) {HDF_LOGE("invalid installer");return HDF_FAILURE;}hostClnt->hostPid = installer->StartDeviceHost(hostClnt->hostId, hostClnt->hostName, dynamic);if (hostClnt->hostPid == HDF_FAILURE) {HDF_LOGW("failed to start device host(%{public}s, %{public}u)", hostClnt->hostName, hostClnt->hostId);return HDF_FAILURE;}hostClnt->stopFlag = false;if (!sync) {return HDF_SUCCESS;}while (hostClnt->hostService == NULL && waitCount > 0) {OsalMSleep(WAIT_HOST_SLEEP_TIME);waitCount--;}if (waitCount <= 0) {HDF_LOGE("wait host(%{public}s, %{public}d) attach timeout", hostClnt->hostName, hostClnt->hostId);hostClnt->hostPid = -1;return HDF_ERR_TIMEOUT;}return HDF_SUCCESS;
}

然后installer->StartDeviceHost

int DriverInstallerFullStartDeviceHost(uint32_t devHostId, const char* devHostName, bool dynamic)
{if (dynamic) {int ret = ServiceControlWithExtra(devHostName, START, NULL, 0);HDF_LOGD("%{public}s %{public}s %{public}d %{public}d", __func__, devHostName, devHostId, ret);}return HDF_SUCCESS;
}

在base/startup/init/interfaces/innerkits/service_control/service_control.c#ServiceControlWithExtra里真正开始启动进程

int ServiceControlWithExtra(const char *serviceName, int action, const char *extArgv[], int extArgc)
{BEGET_ERROR_CHECK(serviceName != NULL, return -1, "Service name is null.");int ret = 0;switch (action) {case START:ret = StartProcess(serviceName, extArgv, extArgc);break;case STOP:ret = StopProcess(serviceName);break;case RESTART:ret = RestartProcess(serviceName, extArgv, extArgc);break;default:BEGET_LOGE("Set service %s action %d error", serviceName, action);ret = -1;break;}return ret;
}

未完待续…

相关文章:

鸿蒙进阶——驱动框架UHDF 机制核心源码解读(一)

文章大纲 引言一、uhdf 概述二、uhdf 的核心参与角色1、drivers/hdf_core/adapter/uhdf2/manager/device_manager.c1.1、drivers/hdf_core/framework/core/manager/src/devmgr_service.c#DevmgrServiceGetInstance通过objectId获取IDevmgrService实例1.2、drivers/hdf_core/fra…...

电子电路:能认为电抗也是在做功吗?

阻抗是什么,我记得在交流电路中,阻抗是电阻、电感和电容的综合作用,用Z表示,单位是欧姆。 那阻抗和做功的关系,可能需要从阻抗的组成来分析。阻抗分为电阻部分和电抗部分,也就是 Z = R + jX,其中R是电阻,X是电抗(包括感抗和容抗)。而做功可能主要和电阻有关,因为电…...

DEEPSEEK + 其他工具的玩法

1. deepseek 即梦&#xff0c;批量生成图片 1&#xff09;给deepseek提出需求&#xff0c;让他生成一个海报设计框架 2&#xff09;让deepseek把上面的框架转换为文生图的提示词&#xff0c;方便用来制作图片 3&#xff09;将提示词复制到 即梦&#xff08;即梦电脑…...

Idea 配合 devtools 依赖 实现热部署

核心依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency> yaml配置 spring: #…...

远程访问家里的路由器:异地访问内网设备或指定端口网址

在一些情况下&#xff0c;我们可能需要远程访问家里的路由器&#xff0c;以便进行设置调整或查看网络状态等&#xff0c;我们看看怎么操作&#xff1f; 1.开启远程访问 在路由本地电脑或手机&#xff0c;登录浏览器访问路由管理后台&#xff0c;并设置开启WEB远程访问。 2.内…...

根据参数量,如何推断需要多少数据才能够使模型得到充分训练?

✅ 一、经验法则&#xff1a;数据量 vs. 模型参数量 经典经验法则&#xff08;适用于监督学习场景&#xff09;&#xff1a; 训练样本数 ≈ 模型参数数量的 10~100 倍对于 BERT-base&#xff08;1.1亿参数&#xff09;&#xff0c;你通常需要 10亿到100亿标注样本 才能从头训…...

PycharmFlask 学习心得:路由(3-4)

对路由的理解&#xff1a; 用户输入网址 例如&#xff1a;http://localhost:5000/hello 浏览器会向这个地址发起一个 HTTP 请求&#xff08;比如 GET 请求&#xff09; 请求到达 Flask 的服务器 Flask 监听着某个端口&#xff08;如 5000&#xff09;&#xff0c;收到请求后…...

从逻辑学视角严谨证明数据加密的数学方法与实践

文章目录 一、加密数据的数学指纹&#xff1a;信息论基础1.1 加密检测的核心原理1.2 香农熵&#xff1a;量化信息的不确定性 二、统计检验方法&#xff1a;从随机性到加密性2.1 卡方检验的数学原理2.2 游程检验与序列相关性2.3 NIST统计测试套件 三、加密算法的特征识别3.1 对称…...

敦煌网测评从环境搭建到风控应对,精细化运营打造安全测评体系

自养号测评&#xff0c;抢占流量为快速提升产品权重和销量&#xff0c;很多卖家常采用自己养号补单测评的方式&#xff0c;技术搭建需要很多要素 一、硬件参数的关联性 在我们使用设备进行注册或操作账号的过程中&#xff0c;系统会记录下大量的系统与网络参数&#xff0c;其中…...

现代化SQLite的构建之旅——解析开源项目Limbo

现代化SQLite的构建之旅——解析开源项目Limbo 在当今飞速发展的技术世界中,轻量级且功能强大的数据库已成为开发者的得力助手。当我们谈论轻量级数据库时,SQLite无疑是一个举足轻重的名字。然而,随着技术的进步,我们对数据库的需求也变得更加多样化。这正是Limbo项目诞生…...

本地分支git push 报错 fatal: The current branch XXXX has no upstream branch.

背景&#xff1a; 我新建了一个本地分支叫做 “新增Saas修改需求”&#xff0c;然后当我提交代码执行 git push时报错如下&#xff0c;并且代码仓库中没有我新建的“新增Saas修改需求”这个分支。 报错信息&#xff1a; 解决方法&#xff1a; 直接采用方法2 ”git push -u orig…...

人工智能100问☞第27问:神经网络与贝叶斯网络的关系?

神经网络与贝叶斯网络是两种互补的智能模型:神经网络通过多层非线性变换从数据中学习复杂模式,擅长大规模特征提取和预测,而贝叶斯网络基于概率推理建模变量间的条件依赖关系,擅长处理不确定性和因果推断。两者的融合(如贝叶斯神经网络)结合了深度学习的表征能力与概率建…...

Python----循环神经网络(WordEmbedding词嵌入)

一、编码 当我们用数字来让电脑“认识”字符或单词时&#xff0c;最简单的方法是为每个字符或单词分配一个唯一的编号&#xff0c;然后用一个长长的向量来表示它。比如&#xff0c;假设“我”这个字在字典中的编号是第10个&#xff0c;那么它的表示就是一个很多0组成的向量&…...

ElasticSearch各种查询语法示例

1. 每种查询语法的区别与优缺点 Query DSL 区别: JSON 格式的结构化查询&#xff0c;功能强大&#xff0c;支持复杂查询逻辑&#xff0c;适用于 Elasticsearch 的核心查询场景。优点: 灵活&#xff0c;功能全面&#xff0c;支持全文搜索、精确匹配、聚合等&#xff1b;可组合…...

CUDA的设备,流处理器(Streams),核,线程块(threadblock),线程,网格(‌gridDim),块(block)和多gpu设备同步数据概念

CUDA的设备,流处理器&#xff0c;核&#xff0c;线程块&#xff08;threadblock&#xff09;&#xff0c;线程&#xff0c;网格&#xff08;‌gridDim&#xff09;&#xff0c;块&#xff08;block&#xff09;和多gpu设备同步数据概念 CUDA的设备,流处理器&#xff0c;核&…...

PyTorch的dataloader制作自定义数据集

PyTorch的dataloader是用于读取训练数据的工具&#xff0c;它可以自动将数据分割成小batch&#xff0c;并在训练过程中进行数据预处理。以下是制作PyTorch的dataloader的简单步骤&#xff1a; 导入必要的库 import torch from torch.utils.data import DataLoader, Dataset定…...

LeetCode 1340. 跳跃游戏 V(困难)

题目描述 给你一个整数数组 arr 和一个整数 d 。每一步你可以从下标 i 跳到&#xff1a; i x &#xff0c;其中 i x < arr.length 且 0 < x < d 。i - x &#xff0c;其中 i - x > 0 且 0 < x < d 。 除此以外&#xff0c;你从下标 i 跳到下标 j 需要满…...

x-cmd install | cargo-selector:优雅管理 Rust 项目二进制与示例,开发体验升级

目录 功能亮点安装优势特点适用场景总结 还在为 Rust 项目中众多的二进制文件和示例而烦恼吗&#xff1f;cargo-selector 让你告别繁琐的命令行&#xff0c;轻松选择并运行目标程序&#xff01; 功能亮点 交互式选择&#xff1a; 在终端中以交互方式浏览你的二进制文件和示例&…...

数据库设计文档撰写攻略

数据库设计文档撰写攻略 一、数据库设计文档的核心价值二、数据库设计文档的核心框架与内容详解2.1 文档基础信息2.2 需求分析与设计原则2.2.1 业务需求概述2.2.2 设计原则 2.3 数据模型设计2.3.1 概念模型&#xff08;ER 图&#xff09;2.3.2 逻辑模型&#xff08;表结构设计&…...

Python爬虫(10)Python数据存储实战:基于pymongo的MongoDB开发深度指南

目录 一、为什么需要文档型数据库&#xff1f;1.1 数据存储的范式变革1.2 pymongo的核心优势 二、pymongo核心操作全解析2.1 环境准备2.2 数据库连接与CRUD操作2.3 聚合管道实战2.4 分批次插入百万级数据&#xff08;进阶&#xff09;2.5 分批次插入百万级数据&#xff08;进阶…...

大模型「瘦身」指南:从LLaMA到MobileBERT的轻量化部署实战

大模型「瘦身」指南&#xff1a;从LLaMA到MobileBERT的轻量化部署实战 系统化学习人工智能网站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目录 大模型「瘦身」指南&#xff1a;从LLaMA到MobileBERT的轻量化部署实战摘要引言一、轻量化技术…...

从逻辑视角学习信息论:概念框架与实践指南

文章目录 一、信息论的逻辑基础与哲学内涵1.1 信息的逻辑本质&#xff1a;区分与差异1.2 逆范围原理与信息内容 二、信息论与逻辑学的概念交汇2.1 熵作为逻辑不确定性的度量2.2 互信息与逻辑依赖2.3 信道容量的逻辑极限 三、信息论的核心原理与逻辑基础3.1 最大熵原理的逻辑正当…...

springboot配置mysql druid连接池,以及连接池参数解释

文章目录 前置配置方式参数解释 前置 springboot 项目javamysqldruid 连接池 配置方式 在 springboot 的 application.yml 中配置基本方式 # Druid 配置&#xff08;Spring Boot YAML 格式&#xff09; spring:datasource:url: jdbc:mysql://localhost:3306/testdb?useSSL…...

Spring Boot集成Resilience4j实现微服务容错机制

在Spring Boot中集成Resilience4j实现微服务容错 引言 在微服务架构中&#xff0c;服务之间的调用不可避免&#xff0c;但由于网络延迟、服务不可用等问题&#xff0c;调用失败的情况时有发生。为了提高系统的稳定性和可用性&#xff0c;我们需要引入容错机制。Resilience4j是…...

(一) 本地hadoop虚拟机系统设置

1.配置固定IP地址&#xff08;每一台都配置&#xff09; 开启node1&#xff0c;修改主机名为node1&#xff0c;并修改固定IP为&#xff1a;192.168.88.131 # 修改主机名 hostnamectl set-hostname node1# 修改IP vim /etc/sysconfig/network-scripts/ifcfg-ens33 IPADDR"…...

TDengine 运维—容量规划

概述 若计划使用 TDengine 搭建一个时序数据平台&#xff0c;须提前对计算资源、存储资源和网络资源进行详细规划&#xff0c;以确保满足业务场景的需求。通常 TDengine 会运行多个进程&#xff0c;包括 taosd、taosadapter、taoskeeper、taos-explorer 和 taosx。 在这些进程…...

【MySQL成神之路】MySQL索引相关介绍

1 相关理论介绍 一、索引基础概念 二、索引类型 1. 按数据结构分类 2. 按功能分类 三、索引数据结构原理 B树索引特点&#xff1a; 哈希索引特点&#xff1a; 四、索引使用原则 1. 创建索引原则 2. 避免索引失效情况 五、索引优化策略 六、索引维护与管理 七、特殊…...

PPP 拨号失败:ATD*99***1# ... failed

从日志来看&#xff0c;主要有两类问题&#xff1a; 一、led_indicator_stop 报 invalid p_handle E (5750) led_indicator: …/led_indicator.c:461 (led_indicator_stop):invalid p_handle原因分析 led_indicator_stop() 的参数 p_handle &#xff08;即之前 led_indicator…...

PostgreSQL跨数据库表字段值复制实战经验分

场景需求 在实际工作中&#xff0c;我们经常需要将一个PostgreSQL数据库中的表字段值复制到另一个数据库中。最近我在处理两个ERP系统数据库&#xff08;A库和B库&#xff09;之间的数据同步时&#xff0c;就遇到了这样的需求&#xff1a;需要将B库中sale_order表的合同信息&a…...

【计网】五六章习题测试

目录 1. (单选题, 3 分)某个网络所分配到的地址块为172.16.0.0/29&#xff0c;能接收目的地址为172.16.0.7的IP分组的最大主机数是&#xff08; &#xff09;。 2. (单选题, 3 分)若将某个“/19”的CIDR地址块划分为7个子块&#xff0c;则可能的最小子块中的可分配IP地址数量…...