深入理解 RDMA 的软硬件交互机制

作者:羽京
一、前言
随着数据中心的飞速发展,高性能网络不断挑战着带宽与时延的极限,网卡带宽从过去的 10 Gb/s 、25 Gb/s 到如今的 100 Gb/s、200 Gb/s 再到下一代的 400Gb/s 网卡,其发展速度已经远大于 CPU 发展的速度。
为了满足高性能网络下的通信需求,阿里云不仅自研了高性能用户态协议栈 (Luna、Solar) ,也大规模使用了 RDMA 技术,以充分利用高性能网络。尤其是在存储和 AI 领域,RDMA 被广泛使用。相比于 Kernel TCP 提供的 Socket 接口,RDMA 的抽象更为复杂,为了更好的使用 RDMA,了解其工作原理和机制是必不可少的。
本文以 NVIDIA (原 Mellanox)的 RDMA 网卡为例,分析其工作原理和软硬件交互的机制。
二、RDMA 是什么
RDMA (Remote Direct Memory Access) 技术全称远程直接内存访问,是为了解决网络传输中服务器端数据处理的延迟而产生的。RDMA 通过网络将数据从一个系统快速移动到另一个系统中,而不需要消耗计算机的处理能力。它消除了内存拷贝和上下文切换的开销,因而能解放内存带宽和 CPU 周期用于提升系统的整体性能。

先看看最常见的 Kernel TCP,其收数据的流程主要要经过以下阶段:
-
网卡驱动从内核分配 dma buffer,填入收队列
-
网卡收到数据包,发起 DMA,写入收队列中的 dma buffer
-
网卡产生中断
-
网卡驱动查看收队列,取出 dma buffer,交给协议栈
-
协议栈处理报文
-
操作系统通知用户态程序有可读事件
-
用户态程序准备 buffer,发起系统调用
-
内核拷贝数据至用户态程序的 buffer 中
-
系统调用结束
可以发现,上述流程有三次上下文切换(中断上下文切换、用户态与内核态上下文切换),有一次内存拷贝。虽然内核有一些优化手段,比如通过 NAPI 机制减少中断数量,但是在高性能场景下, Kernel TCP 的延迟和吞吐的表现依然不佳。
使用 RDMA 技术后,收数据的主要流程变为(以 send/recv 为例):
1)用户态程序分配 buffer,填入收队列
2)网卡收到数据包,发起 DMA,写入收队列中的 buffer
3)网卡产生完成事件(可以不产生中断)
4)用户态程序 polling 完成事件
5)用户态程序处理 buffer
上述流程没有上下文切换,没有数据拷贝,没有协议栈的处理逻辑(卸载到了 RDMA 网卡内),也没有内核的参与。CPU 可以专注处理数据和业务逻辑,不用花大量的 cycles 去处理协议栈和内存拷贝。
三、RDMA 的软件架构
从上述分析可以看出,RDMA 和传统的内核协议栈是完全独立的,因此其软件架构也与内核协议栈很不一样,包含以下部分:

1)用户态驱动(libibverbs、libmlx5 等):这些库都属于 rdma-core 项目(https://github.com/linux-rdma/rdma-core)。为用户提供各种 Verbs API,另外也有一些厂商的特有 API。之所以这层被称为“用户态驱动”,是因为 RDMA 要在用户态直接和硬件打交道,传统在内核态实现 HAL 的方式不满足 RDMA 的需求,因此需要在用户态感知硬件细节。
2)内核态 IB 软件栈:内核态的一层抽象,对应用提供统一的接口。这些接口不仅用户态可以调用,内核态也可以调用。
3) 内核态驱动:各个厂商实现的网卡驱动,直接和硬件交互。
四、RDMA 的内存管理
由于 RDMA 要直接让硬件读写用户态程序的内存,这带来了很多问题:
1)安全问题:用户态程序能否利用网卡读写任意物理内存?
2)地址映射问题:用户态程序使用的是虚拟地址,实际的物理地址是操作系统管理的。网卡怎么知道虚拟地址和物理地址的映射关系?
3)地址映射会变化:操作系统可能会对内存做 swap、压缩,操作系统还有一些复杂的机制,比如 Copy-On-Write。这些情况下,怎么保证网卡访问的地址的正确性?
为了解决上述问题,RDMA 引入了两个概念:
1)PD(Protection Domain):在 RDMA 中,PD 是一个容纳了各种资源的“容器”,类似一个租户 ID,将这些资源纳入自己的保护范围内,避免他们被未经授权的访问。一个进程中可以创建多个 PD,各个 PD 所容纳的资源彼此隔离,无法一起使用。
2)MR(Memory Registration):RDMA 中对内存保护的一种措施,只有将要操作的内存注册到 MR 中,这段内存才能被 RDMA 使用。MR 包括了 PD、lkey、rkey、地址、长度、权限这几个属性。PD 是这个 MR 所属的保护域,其他保护域的上下文是不能访问这个 MR 的(避免了暴力遍历内存访问其他进程内存的可能)。lkey、rkey 统称为 mkey 是一个访问内存的凭据(分别对应本地访问和远程访问),RDMA 的所有操作都要有 mkey 才能进行。
这样讲可能会有一些抽象,以一个实际的例子来看看 RDMA 是怎么注册内存的:
// 扫描 RDMA 设备,找到我们要用的设备
int num_devices = 0, i;
struct ibv_device ** device_list = ibv_get_device_list(&num_devices);
struct ibv_device *device = NULL;
for (i = 0; i < num_devices; ++i) {
if (strcmp("mlx5_bond_0", ibv_get_device_name(device_list[i])) == 0) {
device = device_list[i];
break;
}
}
// 打开设备,产生一个 context
struct ibv_context *ibv_ctx = ibv_open_device(device);
// 分配一个 PD
struct ibv_pd* pd = ibv_alloc_pd(ibv_ctx);
// 分配 8k 内存, 按照 page 对齐(4k)
void *alloc_region = NULL;
posix_memalign(&alloc_region, sysconf(_SC_PAGESIZE), 8192);
// 注册内存
struct ibv_mr* reg_mr = ibv_reg_mr(pd, alloc_region, mr_len, IBV_ACCESS_LOCAL_WRITE);
打开内核模块的 debug 信息:
echo "file mr.c +p" > /sys/kernel/debug/dynamic_debug/control
echo "file mem.c +p" > /sys/kernel/debug/dynamic_debug/control
输出的日志:
infiniband mlx5_0: mlx5_ib_reg_user_mr:1300:(pid 100804): start 0xdb1000, virt_addr 0xdb1000, length 0x2000, access_flags 0x100007
infiniband mlx5_0: mr_umem_get:834:(pid 100804): npages 2, ncont 2, order 1, page_shift 12
infiniband mlx5_0: get_cache_mr:484:(pid 100804): order 2, cache index 0
infiniband mlx5_0: mlx5_ib_reg_user_mr:1369:(pid 100804): mkey 0xdd5d
infiniband mlx5_0: __mlx5_ib_populate_pas:158:(pid 100804): pas[0] 0x3e07a92003
infiniband mlx5_0: __mlx5_ib_populate_pas:158:(pid 100804): pas[1] 0x3e106a6003
1)用户态程序调用 ibv_reg_mr,通过 uverbs 接口发到内核(实际用的系统调用为 ioctl 或者 write),操作的文件是 /dev/infiniband/uverbsX
2)经过 uverbs 层的转换后,最终调用到设备驱动的代码,NVIDIA 网卡上是 mlx5_ib_reg_user_mr 这个函数:

这个函数主要做了两件事情,通过 mr_umem_get 将用户态内存 pin 住,并拿到物理地址。以及通过 reg_create 向网卡发送创建 mkey 的命令。mr_umem_get 最终会调用到 ib_core.ko 中的 __ib_umem_get 函数:

这个函数会通过内核的 pin_user_pages_fast 接口,防止用户内存的映射关系发生意外的改变(比如 swap)。
reg_create 会按照网卡开发手册定义的命令格式,发送创建 mkey 的命令:

经过上述流程,最终会在网卡中创建一个 mkey 对象:
mkey 0xdd5d
virt_addr 0xdb1000, length 0x2000, access_flags 0x100007
pas[0] 0x3e07a92003
pas[1] 0x3e106a6003
网卡收到虚拟地址的时候,就能够知道实际的物理页是什么,并且可以做权限控制。
现在可以回答上面的问题了:
安全问题:用户态程序能否利用网卡读写任意物理内存?
-
不能,RDMA 通过 PD 和 MR 机制做了严格的内存保护。
地址映射问题:用户态程序使用的是虚拟地址,实际的物理地址是操作系统管理的。网卡怎么知道虚拟地址和物理的映射关系?
-
驱动会告诉网卡映射关系,后续数据流中,网卡自己转换。
地址映射会变化:操作系统可能会对内存做 swap、压缩,操作系统还有一些复杂的机制,比如 Copy-On-Write。这些情况下,怎么保证网卡访问的地址的正确性?
-
通过驱动调用 pin_user_pages_fast 保障。另外,用户态驱动会给注册的内存打上 DONT_FORK 的标志,避免 Copy-On-Write 发生。
五、RDMA 的软硬交互
RDMA 的软硬交换的基础单元是 Work Queue。Work Queue 是一个单生产者单消费者的环形队列。Work Queue 根据功能不同,主要分为 SQ(发送)、RQ(接收)、CQ(完成)和 EQ(事件)等。

发送一个 RDMA 请求的大致流程为:
-
软件构造 WQE (Work Queue Element),提交至 Work Queue 中
-
软件写 Doorbell 通知硬件
-
硬件拉取 WQE,处理 WQE
-
硬件处理完成,产生 CQE,写入 CQ
-
硬件产生中断(可选)
-
软件 Polling CQ
-
软件读取硬件更新后的 CQE,得知 WQE 完成
还是以一个实际的例子进行分析,这样才能深入理解全流程:
uint32_t send_demo(struct ibv_qp *qp, struct ibv_mr *mr)
{
struct ibv_send_wr sq_wr = {}, *bad_wr_send = NULL;
struct ibv_sge sq_wr_sge[1];
// 把 mr 的数据发送出去
sq_wr_sge[0].lkey = mr->lkey;
sq_wr_sge[0].addr = (uint64_t)mr->addr;
sq_wr_sge[0].length = mr->length;
sq_wr.next = NULL;
sq_wr.wr_id = 0x31415926; // 请求的ID, 收到 WC 的时候可以对应上
sq_wr.send_flags = IBV_SEND_SIGNALED; // 告诉网卡这个请求给我产生 CQE
sq_wr.opcode = IBV_WR_SEND;
sq_wr.sg_list = sq_wr_sge;
sq_wr.num_sge = 1;
ibv_post_send(qp, &sq_wr, &bad_wr_send); // 提交请求到网卡
struct ibv_wc wc = {};
while (ibv_poll_cq(qp->send_cq, 1, &wc) == 0) {
continue;
}
if (wc.status != IBV_WC_SUCCESS || wc.wr_id != 0x31415926) {
exit(__LINE__);
}
return 0;
}
这段代码的核心是 ibv_post_send 和 ibv_poll_cq,ibv_post_send 的用途是向网卡提交请求,ibv_poll_cq 的用途是轮询 CQ,看看是否有请求完成。
另外,IB 规范定义了很多抽象:
-
ibv_send_wr 这个是 SQ 的 WQE 的抽象(不同厂商的网卡 WQE 格式不同)
-
ibv_sge 是数据的抽象,包含 (addr,len,lkey) 三个字段
-
ibv_wc 是 CQE 的抽象,通过 wr_id 和 ibv_send_wr 对应起来
rdma-core 的 debug 打开,可以看到这样的两条日志:
dump wqe at 0x7fc59b357000
0000000a 00115003 00000008 00000000
00000000 c0000000 00000000 00000000
0000022a 00008a0b 00007fc5 9a5b2000
mlx5_get_next_cqe:565: dump cqe for cqn 0x4c2:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00004863 2a39b102 0a001150 00003f00
第一条就是我们调用 ibv_post_send 后,rdma-core 事件向网卡提交的 WQE。
第二条是我们调用 ibv_poll_cq 后,收到网卡给我们的 CQE。
在 NVIDIA 网卡上,ibv_post_send 最终调用的是 _mlx5_post_send:

这个函数的核心功能是:
1)把 ibv_send_wr 翻译为 NVIDIA 网卡的 WQE 格式
2)Doorbell 通知网卡
5.1 填充 WQE
根据 NVIDIA 的手册,一个 Send 请求的 WQE 包含两个部分:
控制段:

数据段:

根据手册的定义,我们解析一下上面日志中的 WQE:

可以看到,和我们软件填的 ibv_send_wr 是相似的。注意到一个细节,我们填的 wr_id 没有出现在 WQE 中,实际上这个 wr_id 是存在 rdma-core 里的。因为 WQE 是按序处理的,收到 CQE 的时候可以找到当初提交的 ibv_send_wr。
5.2 Doorbell 通知网卡
post_send_db 这个函数很简单,但是细节非常多:

首先,这个函数会加一个内存屏障,保证 Doorbell 到达硬件时,前面构建的 WQE 已经可见。
然后,更新 QP 的 Doorbell 信息(其实就是队列的 tail)
最后,通过 mmio_write64_be 写网卡的寄存器,告诉网卡我准备好了,你可以发了。
mmio_write64_be 使用的是 sse 指令(x86 上),WQE 的第一部分(上文的控制段)写入网卡的寄存器:

实际上就是一个赋值操作,等效于:
*(uint64_t)(bf->reg + bf->offset) = *(uint64_t *)ctrl;
使用 SSE 主要是为了保证原子性,避免网卡先收到前 4 字节,再收到后 4 字节。
看来所有的魔法都在 bf->reg 上,这个 buffer 是什么?为什么软件往这个 buffer 写一个 uint64,网卡就能收到事件?
gdb 中可以看到这个 bf->reg 看起来是一个平平无奇的虚拟地址,但是 gdb 读取会失败。

看看进程的 maps 信息:

这段内存被映射成 Write Only 了,所以读取失败。那这段内存是什么呢?
用 crash 看看页表吧:

物理地址是 1bffc020800,通过 /proc/iomem 可以看到这个物理地址是属于 0000:3b:00.0 这个 PCI 设备的:

这个设备正是我们用的 RDMA 网卡,这个地址位于 BAR0:

根据 NVIDIA 的手册,软件写的这个地址区域被称为 UAR(User Access Region)。UAR 是 PCI 地址空间的一部分,被网卡驱动直接映射至应用的内存中。当软件往 UAR 写 Doorbell 后,网卡会从 PCI 上收到报文,从而获知软件需要发送数据了这件事情。

随后,网卡会经过调度和仲裁,拉取 WQE 进行执行。在执行过程中,网卡会先从 WQE 中提取 mkey 和地址,然后送进 TPT (Translation and Protection)单元中查询 mkey 的信息,拿到地址和权限,校验通过后进行 DMA,最后把数据发送至物理接口。
当数据发送完成,且被对端确认后,网卡会产生 CQE 通知软件。软件收到 CQE 后才可以进行资源的回收。这点和 Socket 接口不同,Socket 接口是有拷贝的,软件调用 write 结束后,就可以把资源回收,而 RDMA 是零拷贝的,资源的生命周期管理会更加复杂。
六、总结
至此,RDMA 基本的工作原理和软硬件交互的机制就介绍完了。RDMA 技术的出发点很简单,就是能不能饶过一切限制,直接把数据送到用户手中。在此之上,做了非常多的工作,成为了一个非常复杂的技术。
RDMA 也不是银弹,有着编程复杂、调试复杂、硬件依赖重、不能长传等问题。对于 IO 密集型的业务,RDMA 可以节约很多 CPU,获得高吞吐低延迟的性能;而对于计算密集的业务,或者追求硬件无关的业务,TCP 是更合适的选择。
参考资料
[01] IB 规范:
https://www.infinibandta.org/ibta-specification/
[02] NVIDIA 网卡手册:
https://network.nvidia.com/files/doc-2020/ethernet-adapters-programming-manual.pdf
相关文章:

深入理解 RDMA 的软硬件交互机制
作者:羽京 一、前言 随着数据中心的飞速发展,高性能网络不断挑战着带宽与时延的极限,网卡带宽从过去的 10 Gb/s 、25 Gb/s 到如今的 100 Gb/s、200 Gb/s 再到下一代的 400Gb/s 网卡,其发展速度已经远大于 CPU 发展的速度。 为了…...

轻优图片编辑压缩官网 轻优图片编辑压缩
轻优图片编辑压缩是一个无需安装,可以直接在线压缩图片大小的网站。轻优图片编辑压缩网站可以快速把图片压缩到指定大小。 轻优图片编辑压缩官网网址:www.qingyoubianji.com 浏览器打开 www.qingyoubianji.com 网站,你会看到一个简洁的界面…...

封装el-table 基于element封装可配置JSON表格组件
基于element封装可配置JSON表格组件 话不多说直接贴代码,复制运行即可查看效果 子组件全部代码 <template><div class"custom-table"><el-table:data"tableData"borderstyle"width: 100%"size"mini"max-h…...

Springboot 开发之 Quartz 任务调度框架简介
引言 Quartz Scheduler是一个功能丰富的开源作业调度库,它允许开发人员以灵活的方式创建和管理定时任务。以下是对Quartz Scheduler的详细解析: 官网地址:https://www.quartz-scheduler.org/w3cschool 官方文档:https://www.w3c…...

详解Xilinx FPGA高速串行收发器GTX/GTP(4)--TX/RX接口的数据位宽和时钟设计
目录 1、时钟设计 2、TX接口 3、接口位宽与时钟的关系 4、时钟来源方案 5、TX端内部的时钟分频设计 6、RX接口 文章总目录点这里:《FPGA接口与协议》专栏的说明与导航 1、时钟设计 GT收发器内部比较复杂,所使用的时钟就不止一个,比较主要的时钟有两个,架构…...
idea个人常用快捷键设置
个人开发者自查便于新环境配置快速查阅,统一windows与mac快捷键设置,有相同习惯的同学可自取。如果有一天你的快捷键不好用了,请一定记得看这篇文章,整理不易,留下关注再走呗。 基本操作快捷键 操作中文名称操作名快捷…...

超实用 不再担心猫咪掉毛 一文教你养宠家庭空气净化器怎么选
一到夏天,家中的猫咪给你带来的不仅仅是温暖的陪伴,还有那挥之不去的宠物异味。普通空气净化器虽然能够应对一般的空气净化需求,但对于养猫家庭特有的挑战,如宠物毛发、皮屑和异味等,它们往往难以胜任。专业的宠物空气…...
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
文章目录 一、HTTP/2 特性实现:nghttp2 源码剖析1.1 二进制帧1.2 多路复用1.3 头部压缩1.4 服务器推送1.5 总结 二、使用 nghttp2 库创建一个 HTTP/2 客户端三、结语 在互联网时代,网络传输协议的作用至关重要。在本文中,我们将对 HTTP/2 的一…...

如何在印尼新闻媒体发布新闻稿件:通稿宣发的好处
如何在印尼新闻媒体发布新闻稿件:通稿宣发的好处 在全球化的时代,新闻稿件的发布和传播对于企业、组织或个人来说至关重要。尤其在印尼这样的东南亚国家,新闻媒体的力量不容忽视。本文将探讨在印尼新闻媒体发布新闻稿件的优势,以…...
如何在 Linux 系统上更改 SSH 服务端口以增强服务器安全性
SSH 服务器默认使用 22 端口,这使得攻击者可以轻松识别并尝试攻击 SSH 服务。为了增加服务器的安全性,建议更改默认的 SSH 端口。本文将详细介绍如何在 Linux 系统上更改 SSH 服务端口,并包含一些最佳实践和注意事项。 1. 检查新的 SSH 端口…...
c++11新特性 -nullptr
今天遇到一道不错的题目,主要讲了c11对nullptr的特性。 首先:nullptr 是C11引入的一个关键字,用于表示“空指针常量”,它是类型std::nullptr_t的唯一值。nullptr 的引入解决了C语言风格的空指针字面量(如NULL或0&#…...
kubernets学习笔记——Kubernets 命令行工具 kubectl
目录 kubectl 的使用方法1、语法2、操作3、资源类型4、输出格式5、示例:常用操作6、示例:创建和使用插件 kubectl 的使用方法 Kubernetes 提供 kubectl 是使用 Kubernetes API 与 Kubernetes 集群的控制面进行通信的命令行工具。这个工具叫做 kubectl。通…...
Hadoop单机及集群部署
目录 一、Hadoop 单机模式部署1. 环境准备2. 安装 Java3. 下载并安装 Hadoop4. 配置环境变量5. 配置 Hadoop编辑 core-site.xml编辑 hdfs-site.xml编辑 mapred-site.xml编辑 yarn-site.xml 6. 格式化 Namenode7. 启动 Hadoop 服务8. 验证 Hadoop注意事项 二、Hadoop 集群模式部…...

使用es-hadoop同步hive和es之间数据
💻近期在华为云连接es时的时候发现不能输入账号密码,后面联系华为工程师了解到,华为云默认是非安全模式,即不需要输入账号密码。 如果对你有所帮助,欢迎点赞收藏关注不迷路哦💓 目录 使用es-hadoop同步h…...
Java - 泛型 + JUnit
一、泛型(参数化类型,在编译时确定) 泛型是一种可以接收数据类型的数据类型(可以这么理解) 作用: 1.能对加入到集合中的数据类型进行约束 2.遍历的时候,不需要进行类型转换,提高效率(因为遍历时,默认的是Object,需要进行类型转换的…...

vue3实现包含表格的Word文件导出
vue3实现包含表格的Word文件导出 近期遇到一个要求,需要在网页上导出Word文档,文档中有表格,也有普通的数据,查阅了很多资料,总算比较完美的解决了,记录一下 先上一下最终效果 演示视频 vue3项目根据Wor…...

【深度学习】TTS,CosyVoice,推理部署的代码原理讲解分享
文章目录 demo代码加载配置文件speech_tokenizer_v1.onnx(只在zero_shot的时候使用)campplus.onnx(只为了提取说话人音色embedding)`campplus_model` 的作用代码解析具体过程解析总结示意图CosyVoiceFrontEndCosyVoiceModel推理过程总体推理过程推理速度很慢: https://git…...
flask高频面试题
目录 高频面试题及答案1. 如何在Flask中处理数据库迁移?2. Flask如何处理文件上传?3. 如何在Flask中处理跨域请求(CORS)?4. 如何在Flask中实现用户认证?5. Flask如何处理会话?6. Flask如何处理表…...
尚硅谷谷粒商城项目笔记——五、使用docker安装mysql
五、使用docker安装mysql 注意: 因为电脑是AMD芯片,自己知识储备不够,无法保证和课程中用到的环境一样,所以环境都是自己根据适应硬件软件环境重新配置的,这里的虚拟机使用的是VMware。 使用 Docker 安装 MySQL 与安…...
filebeat + logstash使用笔记
背景 本文中有2台主机: (1)1.1.1.1是OpenStack的nova节点,安装filebeat (2)1.1.1.2是logstash节点 在1.1.1.1上通过filebeat读取OpenStack的nova-compute组件日志(/var/log/nova/nova-compute.…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...