CANN ops-nn 算子详解:aclnnForeachAddScalarList 张量列表逐元素标量加法接口
CANN ops-nn 算子详解aclnnForeachAddScalarList 张量列表逐元素标量加法接口【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn导读aclnnForeachAddScalarList 是 CANN ops-nn 神经网络算子库中 foreach 系列的高阶组合算子它将张量列表 标量列表整体绑定为一次算子调用对列表中的每个张量逐元素加上对应的标量。本文基于 关联文档 与仓库源码系统讲解其功能语义、产品支持矩阵、两段式 API 原型、参数与错误码约束并给出可直接编译运行的完整调用示例同时深入到 算子定义、内核实现 与底层通用模板 foreach_one_scalar_list_binary.h帮助开发者理解该算子在 NPU 上的执行原理并快速完成二次开发。功能说明与计算公式该接口的功能是输入张量列表和输入标量列表执行逐元素相加运算。也就是说它并不是对单个张量加单个标量而是同时处理一组列表张量和一组列表标量二者按下标一一配对。设输入张量列表为x标量列表为scalars输出张量列表为y三者元素个数均为n$$ x [{x_0}, {x_1}, ... {x_{n-1}}]\ scalars [{scalars_0}, {scalars_1}, ... {scalars_{n-1}}]\ y [{y_0}, {y_1}, ... {y_{n-1}}] $$输出列表中的第i个张量等于输入列表第i个张量与第i个标量逐元素相加的结果$$ y_ix_iscalars_i (i0,1,...n-1) $$从语义上讲该算子等价于 PyTorch 中的torch._foreach_addtensors 与 scalars 均为列表的形态其价值在于把循环调用多个单张量 add 算子合并为一次算子下发减少多次 kernel 启动带来的调度开销尤其适合优化器更新、逐参数加偏置等多个同形状张量执行同一运算的批量场景。仓库中 README 对其定位的描述与之完全一致。产品支持情况该算子在以下产品上受支持与 README 中的支持矩阵一致产品是否支持Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品不支持Kirin X90 处理器系列产品支持Kirin 9030 处理器系列产品支持说明文档aclnnForeachAddScalarList.md的产品支持情况仅列出 6 类产品而仓库 README 额外补充了 Kirin X90 / Kirin 9030 处理器系列两者可相互印证。从 算子定义源码 看该算子通过AICore().AddConfig(ascend950)、AddConfig(ascend910_93)、AddConfig(ascend910b)、AddConfig(kirinx90)、AddConfig(kirin9030)注册了多种核架构配置与上述支持矩阵一一对应。其中 Kirin 系列kirinx90/kirin9030通过GetKirinCoreConfig()单独配置其支持的数据类型收窄为 FLOAT16、FLOAT32、INT32不含 BFLOAT16这一点与 README 中Kirin X90/Kirin 9030 处理器系列产品不支持 BFLOAT16的说明吻合。函数原型两段式接口该算子遵循 CANN 的两段式接口设计必须先调用aclnnForeachAddScalarListGetWorkspaceSize接口获取计算所需 workspace 大小以及包含了算子计算流程的执行器executor再调用aclnnForeachAddScalarList接口执行计算。第一段接口获取 workspace 大小与执行器aclnnStatus aclnnForeachAddScalarListGetWorkspaceSize( const aclTensorList *x, const aclScalarList *scalars, const aclTensorList *out, uint64_t *workspaceSize, aclOpExecutor **executor)第二段接口执行计算aclnnStatus aclnnForeachAddScalarList( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)两段式接口的意义在于第一段在 Host 侧完成入参校验、shape 推导与 workspace 大小计算属于轻量同步调用第二段才真正将算子任务下发到 Stream 上异步执行。开发者需要根据第一段返回的workspaceSize在 Device 侧申请内存并在计算结束后释放。aclnnForeachAddScalarListGetWorkspaceSize 参数说明第一段接口的完整参数如下参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorxaclTensorList*输入表示进行加法运算的输入张量列表对应公式中的x支持空 Tensor该参数中所有 Tensor 的数据类型保持一致FLOAT32、FLOAT16、BFLOAT16、INT32ND0-8√scalarsaclScalarList*输入表示加法运算的输入标量列表对应公式中的scalars元素个数与x中 Tensor 的个数相等数据类型与入参x存在对应关系见下方说明FLOAT32、INT64---outaclTensorList*输出表示进行加法运算的输出张量列表对应公式中的y支持空 Tensor所有 Tensor 数据类型保持一致数据类型和数据格式与入参x一致shape size 大于等于入参x的 shape sizeFLOAT32、FLOAT16、BFLOAT16、INT32ND0-8×workspaceSizeuint64_t*输出返回需要在 Device 侧申请的 workspace 大小-----executoraclOpExecutor**输出返回 op 执行器包含了算子计算流程-----其中scalars与x的数据类型对应关系非常关键直接决定输入组合是否合法当入参x的数据类型为FLOAT32、FLOAT16、BFLOAT16时scalars的数据类型仅支持 FLOAT32当入参x的数据类型为INT32时scalars的数据类型仅支持 INT64。这一规则在源码中有直接依据在 算子定义 中张量侧支持ge::DT_FLOAT16 / ge::DT_FLOAT / ge::DT_INT32 / ge::DT_BF16标量侧则通过DtypeTensor2Scalar工具函数从张量类型映射而来而图模式 IR 定义中scalars的TensorType明确为{DT_FLOAT, DT_INT64}与文档约束完全一致。此外x支持非连续 Tensor表格中 √而out不支持非连续 Tensor×输出张量必须按连续内存组织shape 维度支持 0-8 维0 维即标量张量。从 内核入口 的GET_TILING_DATA与注释foreach(vector) not need workspace可以推断该算子执行时不需要额外的 workspace 计算缓冲第一段接口返回的workspaceSize在多数场景下为 0。返回值与错误码两个接口均返回aclnnStatus状态码具体错误码含义可参考 aclnn返回码。第一段接口完成入参校验在以下场景会报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 x、scalars、out 是空指针ACLNN_ERR_PARAM_INVALID161002x、scalars、out 的数据类型不在支持的范围之内ACLNN_ERR_PARAM_INVALID161002x 和 out 的数据类型不一致ACLNN_ERR_INNER_TILING_ERROR561002x 与 out 的 shape 不满足约束ACLNN_ERR_INNER_TILING_ERROR561002x 或 out 中的 Tensor 数据类型不一致ACLNN_ERR_INNER_TILING_ERROR561002x 或 out 中的 Tensor 维度超过 8 维开发建议调用第一段接口后应优先检查返回码是否为ACL_SUCCESS再根据错误码定位是参数为空161001、类型/形状非法161002还是tiling 计算内部错误561002避免直接带着非法参数进入第二段接口。aclnnForeachAddScalarList 执行接口参数说明第二段接口为纯执行接口参数全部为输入参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnForeachAddScalarListGetWorkspaceSize 获取executor输入op 执行器包含了算子计算流程stream输入指定执行任务的 Stream调用完成后需要通过aclrtSynchronizeStream(stream)同步等待任务执行结束再将结果从 Device 侧拷贝回 Host 侧具体方法见下文调用示例。约束说明确定性计算aclnnForeachAddScalarList为默认确定性实现即在相同输入与运行环境下多次执行结果一致不会引入不确定的并行归约顺序。这一点对依赖可复现结果的训练/调试场景很重要。输出张量不支持非连续 Tensor见上文参数表。Kirin 系列产品不支持 BFLOAT16输入README 与源码双重印证。标量列表元素个数必须与张量列表元素个数相等且遵循上文的数据类型对应关系。调用示例完整可运行的 C 样例文档提供了完整的示例代码仓库中 examples/test_aclnn_foreach_add_scalar_list.cpp 为同源可编译版本整体编译和执行流程可参考 编译与运行样例。下面按文档原样保留完整代码并结合仓库实现做逐步解读。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_foreach_add_scalar_list.h #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vectorint64_t shape) { int64_t shapeSize 1; for (auto i : shape) { shapeSize * i; } return shapeSize; } int Init(int32_t deviceId, aclrtStream* stream) { // 固定写法资源初始化 auto ret aclInit(nullptr); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclInit failed. ERROR: %d\n, ret); return ret); ret aclrtSetDevice(deviceId); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSetDevice failed. ERROR: %d\n, ret); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); return ret); return 0; } template typename T int CreateAclTensor(const std::vectorT hostData, const std::vectorint64_t shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { auto size GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 auto ret aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMalloc failed. ERROR: %d\n, ret); return ret); // 调用aclrtMemcpy将host侧数据复制到device侧内存上 ret aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtMemcpy failed. ERROR: %d\n, ret); return ret); // 计算连续tensor的strides std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1. 固定写法device/stream初始化参考acl API手册 // 根据自己的实际device填写deviceId int32_t deviceId 0; aclrtStream stream; auto ret Init(deviceId, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出需要根据API的接口自定义构造 std::vectorint64_t selfShape1 {2, 3}; std::vectorint64_t selfShape2 {1, 3}; std::vectorint64_t outShape1 {2, 3}; std::vectorint64_t outShape2 {1, 3}; void* input1DeviceAddr nullptr; void* input2DeviceAddr nullptr; void* out1DeviceAddr nullptr; void* out2DeviceAddr nullptr; aclTensor* input1 nullptr; aclTensor* input2 nullptr; aclScalar* alpha1 nullptr; aclScalar* alpha2 nullptr; aclTensor* out1 nullptr; aclTensor* out2 nullptr; std::vectorfloat input1HostData {1, 2, 3, 4, 5, 6}; std::vectorfloat input2HostData {7, 8, 9}; std::vectorfloat out1HostData(6, 0); std::vectorfloat out2HostData(3, 0); float alpha1Value 1.2f; float alpha2Value 2.2f; // 创建input1 aclTensor ret CreateAclTensor(input1HostData, selfShape1, input1DeviceAddr, aclDataType::ACL_FLOAT, input1); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建input2 aclTensor ret CreateAclTensor(input2HostData, selfShape2, input2DeviceAddr, aclDataType::ACL_FLOAT, input2); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建alpha1 aclScalar alpha1 aclCreateScalar(alpha1Value, aclDataType::ACL_FLOAT); CHECK_RET(alpha1 ! nullptr, return ret); // 创建alpha2 aclScalar alpha2 aclCreateScalar(alpha2Value, aclDataType::ACL_FLOAT); CHECK_RET(alpha2 ! nullptr, return ret); // 创建out1 aclTensor ret CreateAclTensor(out1HostData, outShape1, out1DeviceAddr, aclDataType::ACL_FLOAT, out1); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建out2 aclTensor ret CreateAclTensor(out2HostData, outShape2, out2DeviceAddr, aclDataType::ACL_FLOAT, out2); CHECK_RET(ret ACL_SUCCESS, return ret); std::vectoraclTensor* tempInput{input1, input2}; aclTensorList* tensorListInput aclCreateTensorList(tempInput.data(), tempInput.size()); std::vectoraclTensor* tempOutput{out1, out2}; aclTensorList* tensorListOutput aclCreateTensorList(tempOutput.data(), tempOutput.size()); std::vectoraclScalar* tempscalar{alpha1, alpha2}; aclScalarList* scalarlist aclCreateScalarList(tempscalar.data(), tempscalar.size()); // 3. 调用CANN算子库API需要修改为具体的API名称 uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnForeachAddScalarList第一段接口 ret aclnnForeachAddScalarListGetWorkspaceSize(tensorListInput, scalarlist, tensorListOutput, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnForeachAddScalarListGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 void* workspaceAddr nullptr; if (workspaceSize 0) { ret aclrtMalloc(workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); } // 调用aclnnForeachAddScalarList第二段接口 ret aclnnForeachAddScalarList(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnForeachAddScalarList failed. ERROR: %d\n, ret); return ret); // 4. 固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 获取输出的值将device侧内存上的结果复制至host侧需要根据具体API的接口定义修改 auto size GetShapeSize(outShape1); std::vectorfloat out1Data(size, 0); ret aclrtMemcpy(out1Data.data(), out1Data.size() * sizeof(out1Data[0]), out1DeviceAddr, size * sizeof(out1Data[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy result from device to host failed. ERROR: %d\n, ret); return ret); for (int64_t i 0; i size; i) { LOG_PRINT(out1 result[%ld] is: %f\n, i, out1Data[i]); } size GetShapeSize(outShape2); std::vectorfloat out2Data(size, 0); ret aclrtMemcpy(out2Data.data(), out2Data.size() * sizeof(out2Data[0]), out2DeviceAddr, size * sizeof(out2Data[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(copy result from device to host failed. ERROR: %d\n, ret); return ret); for (int64_t i 0; i size; i) { LOG_PRINT(out2 result[%ld] is: %f\n, i, out2Data[i]); } // 6. 释放aclTensor和aclScalar需要根据具体API的接口定义修改 aclDestroyTensorList(tensorListInput); aclDestroyTensorList(tensorListOutput); aclDestroyScalarList(scalarlist); // 7.释放device资源需要根据具体API的接口定义修改 aclrtFree(input1DeviceAddr); aclrtFree(input2DeviceAddr); aclrtFree(out1DeviceAddr); aclrtFree(out2DeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例代码逐段解读资源初始化固定写法aclInit→aclrtSetDevice→aclrtCreateStream完成 ACL 运行时初始化。deviceId需按实际硬件环境填写。构造输入与输出示例构造了两个 FLOAT32 张量shape 分别为{2,3}与{1,3}和两个 FLOAT32 标量1.2f、2.2f。CreateAclTensor模板函数完成 host 数据 → device 内存拷贝并依据 shape 反推连续 strides 后调用aclCreateTensor创建aclTensor标量通过aclCreateScalar创建aclScalar。最后分别用aclCreateTensorList与aclCreateScalarList将多个张量/标量聚合成列表参数。注意由于x为 FLOAT32scalars也必须使用 FLOAT32示例中aclCreateScalar传入ACL_FLOAT正是遵循了前文的数据类型对应规则。调用两段式接口先调aclnnForeachAddScalarListGetWorkspaceSize拿到workspaceSize与executor若workspaceSize 0则用aclrtMalloc申请 device 侧 workspace随后调用aclnnForeachAddScalarList(workspaceAddr, workspaceSize, executor, stream)真正执行。同步等待aclrtSynchronizeStream(stream)保证算子异步执行完成后才读取结果。回拷结果将输出张量从 device 内存aclrtMemcpy回 host 并打印。预期out1为{11.2, 21.2, ..., 61.2}out2为{72.2, 82.2, 92.2}。释放列表资源aclDestroyTensorList、aclDestroyScalarList释放列表句柄。释放 device 资源aclrtFree释放各输入/输出/workspace 内存aclrtDestroyStream、aclrtResetDevice、aclFinalize收尾。结合源码理解底层实现Host 侧算子定义OpDefforeach_add_scalar_list_def.cpp 通过OpDef描述算子的输入输出契约输入xParamType(DYNAMIC)即动态个数的 Tensor 列表支持 FLOAT16 / FLOAT / INT32 / BF16格式 ND并标记AutoContiguous()对应支持非连续 Tensor约束输入scalarsScalarList()ParamType(REQUIRED)即标量列表数据类型由DtypeTensor2Scalar从张量类型映射而来输出yParamType(DYNAMIC)数据类型与x一致AICore 配置开启DynamicCompileStaticFlag(true)、DynamicRankSupportFlag(true)、DynamicShapeSupportFlag(true)即支持动态 shape、动态 rank0-8 维的编译执行这与参数表中shape 0-8 维的约束一一对应。内核侧实现Kernelforeach_add_scalar_list.cpp 是算子内核入口foreach_add_scalar_list通过TILING_KEY_IS(...)按数据类型分发到模板实例TILING_KEY1ForeachOneScalarListBinaryhalf, half, AddsAdapterhalf, 1, 1FLOAT16TILING_KEY2ForeachOneScalarListBinaryfloat, float, AddsAdapterfloat, 1, 1FLOAT32TILING_KEY3__CCE_AICORE__ 220ForeachOneScalarListBinaryint, int, AddsAdapterint, 1, 1INT32TILING_KEY4部分新架构排除 NPU 3003/3113ForeachOneScalarListBinarybfloat16_t, float, AddsAdapterfloat, 1, 1BFLOAT16标量侧用 float 参与计算。其中AddsAdapter是对 AscendC 向量指令Adds(dst, src, scalar, count)的封装——注意标量以单值广播方式参与逐元素运算。从#if __CCE_AICORE__ 220与__NPU_ARCH__的编译期分支可以看出不同架构对 BFLOAT16 / INT32 的支持存在差异这也解释了为何 Kirin 系列不含 BF16与部分旧架构在支持矩阵上的区别。底层通用模板该算子复用了 foreach 系列的通用模板 foreach_one_scalar_list_binary.h。模板类ForeachOneScalarListBinary继承自KernelForeachUnary核心流程为Init中将inScalarGM绑定到标量列表的全局内存SetGlobalBuffer按列表下标取值ProcessPlusInLoop在每次循环迭代开始时通过inScalarGM.GetValue(index)取出与当前张量配对的标量值BFLOAT16 场景先将标量提升为 float 再计算Compute从输入队列取数据、调用InnerComputer执行Adds逐元素加法、结果入输出队列。因此整个内核本质上是对张量列表 标量列表做扁平化的流水处理外层遍历列表元素内层以向量指令完成批量逐元素加法一次 kernel 调用即可处理整组张量避免了逐张量发 kernel 的开销。图模式调用除了 aclnn 接口该算子也支持图模式构图调用。图模式下的算子 IR 定义在 foreach_add_scalar_list_proto.hREG_OP(ForeachAddScalarList)声明了DYNAMIC_INPUT(x, ...)、INPUT(scalars, ...)、DYNAMIC_OUTPUT(y, ...)的图 IR 契约。两种调用方式的差异可参考 README 的调用说明调用方式样例代码说明aclnn 接口test_aclnn_foreach_add_scalar_list通过 aclnnForeachAddScalarList 接口方式调用 ForeachAddScalarList 算子图模式-通过 算子IR 构图方式调用 ForeachAddScalarList 算子测试验证仓库为该算子提供了完整的 UT/ST 测试链可作为二次开发时的行为参照内核 UTtests/ut/op_kernel/test_foreach_add_scalar_list.cpp 通过gen_data.py生成多组 shape如{{128, 64}, {16, 128}, {32, 128}}与 float32/float16 等类型数据利用ICPU_SET_TILING_KEY指定数据类型分支、ICPU_RUN_KF在模拟环境下跑内核再用compare_data.py与 golden 数据比对覆盖多张量列表 多标量列表的批量加法正确性Host 侧 UTtests/ut/op_host/下的test_foreach_add_scalar_list_infershape.cpp与test_foreach_add_scalar_list_tiling.cpp分别验证 shape 推导与 tiling 计算逻辑ST 测试tests/st/aclnnForeachAddScalarList/提供 ATK 用例配置atk_aclnnForeachAddScalarList.json与执行器脚本tests/assets/golden.py生成标准答案配置档op_host/config/下按ascend910_93、ascend910b、ascend950、kirin9030、kirinx90分别提供foreach_add_scalar_list_binary.json与算子定义的 AICore 注册一一对应。总结aclnnForeachAddScalarList 是 CANN ops-nn 中面向批量张量 批量标量逐元素加法场景的 foreach 组合算子支持 FLOAT32 / FLOAT16 / BFLOAT16 / INT32 输入标量分别为 FLOAT32 / INT64覆盖 Ascend 950、A2、A3 及 Kirin 系列产品。开发者只需按两段式接口规范调用即可在 NPU 上高效完成整组张量的标量加法如需深入定制可沿 算子定义 → 内核实现 → 通用模板 的链路理解其数据契约、tiling 分发与向量化计算过程并借助仓库内 UT/ST 测试快速验证改动。【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

使用 ODBC 将 TDengine 接入 SQL Server Reporting Services (SSRS):环境搭建、报表开发与发布全流程指南

使用 ODBC 将 TDengine 接入 SQL Server Reporting Services (SSRS):环境搭建、报表开发与发布全流程指南

数据库时序数据库物联网大数据实时分析云原生 【免费下载链接】tdengine TDengine is an open source, high-performance, cloud native time-series database optimized for Internet of Things (IoT), Connected Cars, Industrial IoT and DevOps. 项目地址: http…

2026/9/21 18:30:28 阅读更多 →
C语言中的运算符表达式

C语言中的运算符表达式

1.算术表达式1>概念算术表达式是用运算符号将常量、变量以及数学函数连接起来的式子。2>算术运算符又分双目运算符和单目运算符两种。每个运算符都要处理两个操作数(即运算数),操作数可以是常量、变量或者其他算数表达式,操…

2026/9/21 18:30:28 阅读更多 →
JVM调优实战:从参数配置到性能优化指南

JVM调优实战:从参数配置到性能优化指南

1. JVM调优实战:从参数配置到性能优化的完整指南在Java应用开发中,JVM调优是每个资深开发者必须掌握的技能。记得我第一次负责生产环境调优时,面对频繁的Full GC和居高不下的CPU使用率,那种手足无措的感觉至今难忘。经过多年实践&…

2026/9/21 18:29:27 阅读更多 →

最新新闻

卓大师下载官网实战:3个细节搞定性能优化

卓大师下载官网实战:3个细节搞定性能优化

卓大师下载官网实战:3个细节搞定性能优化 面试被问原理答不上来,这种尴尬谁没经历过?尤其是聊到下载站这类高并发场景,张口就是“用CDN”、“加缓存”,结果被追问到底层IO阻塞或者数据库连接池泄漏,瞬间哑火。其实, 性能优化…

2026/9/21 18:56:42 阅读更多 →
小程序在线生成避坑指南,速查手册助你告别报错

小程序在线生成避坑指南,速查手册助你告别报错

小程序在线生成避坑指南,速查手册助你告别报错 盯着屏幕上的红色 StackTrace,是不是感觉脑瓜子嗡嗡的?那一长串 TypeError 和 ReferenceError…

2026/9/21 18:56:42 阅读更多 →
3个真实踩坑案例:dps文件解析避坑指南,面试不再卡壳

3个真实踩坑案例:dps文件解析避坑指南,面试不再卡壳

3个真实踩坑案例:dps文件解析避坑指南,面试不再卡壳 配置环境就卡半天,排查日志两小时,最后发现是 dps 文件解析逻辑写错了?别慌,这场景我见过太多次了。今天这篇 dps 文件 避坑指南…

2026/9/21 18:56:42 阅读更多 →
Paseo Committee Skill:以双高推理 Agent 委员会做根因分析与复杂规划

Paseo Committee Skill:以双高推理 Agent 委员会做根因分析与复杂规划

Paseo Committee Skill:以双高推理 Agent 委员会做根因分析与复杂规划 【免费下载链接】paseo Orchestrate multiple coding agents from desktop and mobile 项目地址: https://gitcode.com/gh_mirrors/pa/paseo 导读 当主 Agent 陷入死循环、反复兜圈子、…

2026/9/21 18:56:42 阅读更多 →
emmet插件底层图解原理:告别配置卡壳,3分钟掌握核心逻辑

emmet插件底层图解原理:告别配置卡壳,3分钟掌握核心逻辑

emmet插件底层图解原理:告别配置卡壳,3分钟掌握核心逻辑 配置环境就卡半天,这是很多开发者接触前端工具链时的真实写照。你明明只想快速写几个 div 标签,结果却要在 VS Code 设置里翻找半天,或者对着文档上的 !…

2026/9/21 18:56:42 阅读更多 →
Vibe 语音转写工具:离线批量转录的高效实战指南

Vibe 语音转写工具:离线批量转录的高效实战指南

Vibe 语音转写工具:离线批量转录的高效实战指南 【免费下载链接】vibe Transcribe on your own! 项目地址: https://gitcode.com/GitHub_Trending/vib/vibe Vibe 是一款基于 Whisper 引擎的本地语音转写工具,全程在你的设备上运行。它能离线转录音…

2026/9/21 18:55:41 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →