C语言性能优化:从基础到高级的全面指南
引言
C 语言以其高效、灵活和功能强大而著称,被广泛应用于系统编程、嵌入式开发、游戏开发等领域。然而,要写出高性能的 C 语言代码,需要对 C 语言的特性和底层硬件有深入的了解。本文将详细介绍 C 语言性能优化的背后技术,并通过具体的代码示例来展示如何实现性能优化。本文分为多个部分,从基本概念和技巧到高级性能优化技术,全面覆盖 C 语言性能优化的各个方面。
1. 基本概念和技巧
1.1 数据对齐
数据对齐是指数据的内存地址与数据大小的整数倍对齐。大多数现代计算机系统都要求数据对齐,因为对齐的数据访问速度更快。在 C 语言中,可以通过 #pragma pack
指令来设置数据对齐的方式。
#include <stdio.h>
#pragma pack(1) // 设置数据对齐为1字节
struct Example {char a;int b;char c;
};
#pragma pack() // 恢复默认数据对齐方式int main() {struct Example ex;printf("Size of struct: %zu\n", sizeof(ex)); // 输出结构体大小return 0;
}
在上面的代码中,通过设置 #pragma pack(1)
,将数据对齐方式设置为 1 字节。这样,结构体 Example
中的数据将按照 1 字节对齐,而不是默认的 4 字节对齐。这会导致结构体的大小变小,但可能会降低访问速度。因此,在实际开发中,需要根据具体情况来选择合适的数据对齐方式。
1.2 循环展开
循环展开是一种通过增加每次迭代中执行的操作数来减少循环次数的技术。这可以减少循环的开销,提高代码的执行速度。
#include <stdio.h>void loop_unrolling(int *arr, int n, int value) {int i;for (i = 0; i < n; i += 2) {arr[i] = value;arr[i + 1] = value;}
}int main() {int arr[10];loop_unrolling(arr, 10, 5);for (int i = 0; i < 10; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}
在上面的代码中,通过将每次迭代中的操作数从 1 增加到 2,将循环次数减少了一半。这样可以减少循环的开销,提高代码的执行速度。但需要注意的是,循环展开会增加代码的大小,因此需要根据具体情况来选择是否使用循环展开。
1.3 函数内联
函数内联是一种通过将函数调用展开为函数体来减少函数调用开销的技术。在 C 语言中,可以通过 inline
关键字来声明内联函数。
#include <stdio.h>inline int add(int a, int b) {return a + b;
}int main() {int result = add(3, 4);printf("Result: %d\n", result);return 0;
}
在上面的代码中,通过将 add
函数声明为内联函数,编译器会将函数调用展开为函数体,从而减少函数调用的开销。但需要注意的是,内联函数会增加代码的大小,因此需要根据具体情况来选择是否使用内联函数。
2. 编译器优化
2.1 编译器选项
编译器提供了多种优化选项,这些选项可以影响编译过程,从而生成更高效的机器代码。以下是一些常用的编译器优化选项。
-O0
:无优化(默认选项),用于调试。-O1
:一级优化,主要包括去除冗余代码、常量折叠等,不会进行复杂的优化。-O2
:二级优化,除了包含一级优化的所有内容外,还包括循环展开、指令重排等。-O3
:三级优化,在二级优化的基础上,增加更多的优化措施,如自动向量化。-Ofast
:允许编译器进行一些可能违反语言标准的优化,通常能提供更高的性能。-march=native
:启用针对本机 CPU 架构的优化,使得生成的代码能够更好地利用特定硬件的特性。
gcc -O0 -o compute_O0 compute.c # 无优化版本
gcc -O1 -o compute_O1 compute.c # 一级优化版本
gcc -O2 -o compute_O2 compute.c # 二级优化版本
gcc -O3 -o compute_O3 compute.c # 三级优化版本
gcc -Ofast -o compute_Ofast compute.c # 可能违反标准的优化版本
gcc -march=native -o compute_native compute.c # 针对本地架构优化版本
通过比较不同优化级别的执行时间,可以选择最适合当前程序的优化选项。
2.2 编译器内置函数
现代编译器通常提供一些内置函数,这些函数可以替代标准库函数或手动编写的代码,以提供更好的性能。
__builtin_expect
:用于分支预测优化。__builtin_prefetch
:用于数据预取,以减少缓存未命中的次数。
#include <stdio.h>// 假设我们有一个检查错误码的函数
int error_check(int error_code) {if (error_code == 0) {// 正常情况} else {// 错误处理}
}// 使用 __builtin_expect 优化
int error_check_optimized(int error_code) {if (__builtin_expect(error_code, 0)) {// 错误处理} else {// 正常情况}
}int main() {int result = error_check_optimized(0);return 0;
}
在这个例子中,我们假设 error_code
很可能为 0,那么这个分支就不太可能被执行。通过使用 __builtin_expect
,可以优化分支预测,提高性能。
3. 高级性能优化技术
3.1 缓存优化
现代计算机体系结构中,缓存是提高数据访问速度的关键组件。理解缓存的工作原理对于优化程序性能至关重要。缓存优化主要包括两个方面:缓存行利用和减少缓存失效。
3.1.1 缓存行利用
缓存是由缓存行组成的,通常是 64 字节。当数据被加载到缓存中时,它会填充整个缓存行。因此,连续的数据访问(如数组访问)可以充分利用缓存行,提高数据访问的局部性。
#include <stdio.h>void cache_line_utilization(int *arr, int n) {for (int i = 0; i < n; i++) {arr[i] = i;}
}int main() {int n = 1024;int arr[n];cache_line_utilization(arr, n);// ...后续使用 arr 的代码...return 0;
}
在上面的代码中,cache_line_utilization
函数通过连续访问数组 arr
来充分利用缓存行,从而提高性能。
3.1.2 减少缓存失效
缓存失效是指缓存中的数据不再有效,需要从主存中重新加载。减少缓存失效可以提高程序性能。
#include <stdio.h>void reduce_cache_misses(int *arr, int n) {for (int i = 0; i < n; i += 64) { // 64 是假设的缓存行大小for (int j = 0; j < 64 && i + j < n; j++) {arr[i + j] = i + j;}}
}int main() {int n = 1024;int arr[n];reduce_cache_misses(arr, n);// ...后续使用 arr 的代码...return 0;
}
在上面的代码中,reduce_cache_misses
函数通过减少跨缓存行的跳跃来减少缓存失效,从而提高性能。
3.2 指令级优化
指令级优化涉及到编译器和处理器的指令集架构。通过理解和利用这些底层细节,可以编写出更高效的代码。
3.2.1 循环展开和向量化
现代处理器通常支持 SIMD(单指令多数据)指令,允许同时对多个数据执行相同的操作。通过循环展开和向量化,可以利用这些指令来提高性能。
#include <stdio.h>
#include <emmintrin.h> // SSE 指令集void vectorization(int *arr, int n, int value) {for (int i = 0; i < n; i += 4) {__m128i vec = _mm_set1_epi32(value); // 创建一个包含 value 的向量_mm_storeu_si128((__m128i *)&arr[i], vec); // 将向量存储到 arr 中}
}int main() {int n = 1024;int arr[n];vectorization(arr, n, 5);// ...后续使用 arr 的代码...return 0;
}
在上面的代码中,我们使用了 SSE 指令集来实现向量化。这种方法可以显著提高性能,尤其是在处理大型数据集时。
3.2.2 分支预测优化
现代处理器使用分支预测来猜测程序的控制流,以提高指令流水线的效率。优化分支可以提高性能。
#include <stdio.h>int main() {int arr[1024];for (int i = 0; i < 1024; i++) {arr[i] = i % 2 == 0 ? i : -i;}// ...后续使用 arr 的代码...return 0;
}
在这个例子中,我们通过条件表达式来优化分支,减少不必要的分支预测错误。
4. 内存管理优化
4.1 静态分配与动态分配
静态分配和动态分配各有优缺点。静态分配在编译时确定内存大小,适用于大小固定的数组。动态分配在运行时确定内存大小,适用于大小不确定的数组。
#include <stdio.h>
#include <stdlib.h>int main() {// 静态分配数组int arr[100];// 动态分配数组int *dynArr = malloc(100 * sizeof(int));if (dynArr == NULL) {fprintf(stderr, "Memory allocation failed\n");exit(EXIT_FAILURE);}// 使用 dynArr 进行操作for (int i = 0; i < 100; i++) {dynArr[i] = i;}// 释放内存free(dynArr);return 0;
}
在上面的代码中,我们展示了静态分配和动态分配的区别,并演示了如何动态分配和释放内存。
4.2 内存对齐
适当对齐数据结构可以提高内存访问速度。减少缓存未命中,提高性能。
#include <stdio.h>
#include <stdalign.h>struct Example {int a;char b;double c;
} __attribute__((aligned(8)));int main() {struct Example ex;printf("Size of struct: %zu\n", sizeof(ex)); // 输出结构体大小return 0;
}
在上面的代码中,通过指定 __attribute__((aligned(8)))
,我们确保结构体的每个实例在内存中从 8 的倍数地址开始,这有助于提高内存访问的效率,尤其是在 64 位处理器上。
4.3 避免内存泄漏
合理管理动态分配的内存,避免内存泄漏。对于长期运行的程序尤为重要。
#include <stdio.h>
#include <stdlib.h>int main() {int *ptr = malloc(100 * sizeof(int));if (ptr == NULL) {fprintf(stderr, "Memory allocation failed\n");exit(EXIT_FAILURE);}// 使用 ptr 进行操作for (int i = 0; i < 100; i++) {ptr[i] = i;}// 释放内存free(ptr);return 0;
}
在上面的代码中,我们展示了如何动态分配内存并在使用完毕后释放内存,避免内存泄漏。
5. 算法和数据结构优化
5.1 选择合适的算法和数据结构
选择合适的算法和数据结构可以显著提高程序的效率。例如,对于需要频繁插入和删除操作的数据,使用链表比使用数组更高效。
#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node *next;
} Node;void insert(Node **head, int value) {Node *new_node = (Node *)malloc(sizeof(Node));new_node->data = value;new_node->next = *head;*head = new_node;
}int main() {Node *head = NULL;insert(&head, 1);insert(&head, 2);// ...后续操作...return 0;
}
在上面的代码中,我们使用链表来实现插入和删除操作,相比于数组,链表的插入和删除操作更高效。
5.2 查表优化
查表是一种常见的优化技术,特别是在需要频繁进行相同计算的情况下。通过预先计算并将结果存储在表中,可以避免在运行时重复计算。
#include <stdio.h>static long factorial_table[] = {1, 1, 2, 6, 24, 120, 720 /* etc */ };long factorial(int i) {return factorial_table[i];
}int main() {int i = 5;printf("Factorial of %d is %ld\n", i, factorial(i));return 0;
}
在上面的代码中,我们预先计算了阶乘值并存储在 factorial_table
数组中,通过查表来获取阶乘值,避免了在运行时重复计算。
5.3 使用位操作
位操作可以直接操作数据的最小单元——位,常用于优化数据结构和实现加密算法。
#include <stdio.h>int main() {unsigned char flags = 0;flags |= (1 << 2); // 设置第3位flags &= ~(1 << 2); // 清除第3位printf("Flags: %02X\n", flags);return 0;
}
在上面的代码中,我们使用位操作来设置和清除特定的位,这种方式比使用布尔变量更高效。
6. 并行计算和多线程优化
6.1 使用多线程
多线程可以充分利用多核处理器的计算能力,提高程序的执行效率。C 语言中可以使用 POSIX 线程库(pthread)来实现多线程。
#include <stdio.h>
#include <pthread.h>void *thread_function(void *arg) {int *data = (int *)arg;for (int i = 0; i < 1000000; i++) {(*data)++;}return NULL;
}int main() {pthread_t threads[4];int data[4] = {0};for (int i = 0; i < 4; i++) {pthread_create(&threads[i], NULL, thread_function, &data[i]);}for (int i = 0; i < 4; i++) {pthread_join(threads[i], NULL);}for (int i = 0; i < 4; i++) {printf("Thread %d result: %d\n", i, data[i]);}return 0;
}
在上面的代码中,我们创建了 4 个线程,每个线程独立地对一个整数进行累加操作。通过多线程,可以显著提高计算效率。
6.2 使用 OpenMP
OpenMP 是一种并行编程模型,可以简化多线程编程。通过在代码中添加简单的指令,可以轻松实现并行计算。
#include <omp.h>
#include <stdio.h>int main() {int sum = 0;#pragma omp parallel for reduction(+:sum)for (int i = 0; i < 1000000; i++) {sum += i;}printf("Sum: %d\n", sum);return 0;
}
在上面的代码中,我们使用 OpenMP 的 #pragma omp parallel for
指令将循环并行化,并使用 reduction
子句来处理累加操作。通过这种方式,可以显著提高计算效率。
7. 性能分析和调试
7.1 使用性能分析工具
为了有效地进行性能优化,需要使用一系列的性能分析工具来识别和诊断性能瓶颈。以下是一些常用的性能分析工具及其使用场景。
- gprof:一个功能强大的性能分析工具,可以显示程序运行的 CPU 时间分布,帮助开发者找到优化的热点。
- Valgrind:一个编程工具,主要用于内存调试、内存泄漏检测和性能分析。其性能分析工具 Callgrind 可以生成详细的调用图和性能数据。
- perf:Linux 内核提供的一个性能分析工具,可以用来分析程序的性能问题,特别是 CPU 缓存使用、分支预测等方面。
# 使用 gprof
gcc -pg -o my_program my_program.c
./my_program
gprof my_program > profile.txt# 使用 Valgrind
valgrind --tool=callgrind ./my_program# 使用 perf
perf record -g ./my_program
perf report
7.2 性能优化原则
在进行性能优化时,应遵循以下原则:
- 先测量,后优化:不要基于猜测进行优化,而是要通过测量来确定性能瓶颈。
- 关注主要矛盾:优化那些对性能影响最大的部分,遵循 80/20 法则。
- 逐步迭代:性能优化是一个迭代过程,需要逐步调整和验证。
- 保持代码可读性:在优化性能的同时,尽量保持代码的清晰和可维护性。
8. 实际应用案例
8.1 用户输入验证
在实际开发中,用户输入验证是一个常见的应用场景。通过 scanf
函数可以方便地读取用户的输入并进行验证。
#include <stdio.h>
#include <stdlib.h>int main() {int age;printf("请输入您的年龄:");if (scanf("%d", &age) != 1 || age <= 0) {printf("无效的年龄输入!\n");return 1;}printf("您的年龄:%d\n", age);return 0;
}
8.2 文件读取
scanf
函数可以结合文件输入流读取文件中的数据。
#include <stdio.h>int main() {FILE *file = fopen("data.txt", "r");if (file == NULL) {perror("文件打开失败");return 1;}int a, b;if (fscanf(file, "%d %d", &a, &b) != 2) {printf("文件读取错误!\n");fclose(file);return 1;}printf("文件中的数据:a = %d, b = %d\n", a, b);fclose(file);return 0;
}
8.3 数据解析
scanf
函数可以用于解析复杂的输入数据格式。
#include <stdio.h>int main() {char name[50];int age;float salary;printf("请输入员工信息(姓名 年龄 薪水):");if (scanf("%49s%d%f", name, &age, &salary) != 3) {printf("输入格式错误!\n");return 1;}printf("员工信息:姓名:%s,年龄:%d,薪水:%.2f\n", name, age, salary);return 0;
}
9. 总结
C 语言因其高效、灵活和功能强大而广受欢迎。通过理解底层优化、编译器优化、内存管理和高级编程技巧,程序员可以编写出性能卓越的 C 程序。本文提供了详细的优化策略和代码案例,希望对读者深入理解 C 语言性能优化有所帮助。在实际应用中,性能优化是一个复杂的过程,需要根据具体的应用场景和目标平台进行细致的分析和调整。
参考文献
[1] C语言代码优化11种实用方法 - 知乎
[2] C语言程序性能优化:十大策略及代码案例解析
[3] C语言代码优化艺术:深入细节,提升效率与性能的实践指南
[4] 高性能计算|C语言常见优化策略 - 知乎
[5] C语言性能优化 - 裸睡的猪 - 博客园
[6] 超全 | 只有高手才知道的C语言高效编程与代码优化方法(一 …
[7] C语言性能优化 - CSDN博客
[8] C语言代码优化方法详解 - CSDN博客
[9] 优化C/C++代码性能的27条建议——<Tips for Optimizing C …
[10] 18|极致优化(上):如何实现高性能的 C 程序?
[11] C语言代码性能优化:提升程序效率的10大技巧 - CSDN文库
[12] C语言性能深度剖析:从底层优化到高级技巧及实战案例分析
[13] C语言性能优化参考手册 - CSDN博客
[14] C语言程序性能优化:十大策略及代码案例解析
[15] 性能优化技巧:C语言程序的高效实现 - CSDN文库
[16] C语言代码优化实战指南与案例分析 - CSDN文库
[17] [大师C语言 (第十篇)]C语言性能优化的技术详解_c语言性能 …
[18] 如何在C语言中优化代码性能 - PingCode
[19] 高性能计算|C语言常见优化策略 - 知乎
[20] 19|极致优化(下):如何实现高性能的 C 程序?-深入C语言 …
[21] 【C 言专栏】优化 C 语言程序性能的策略 - 阿里云开发者社区
[22] c语言如何提高性能 | PingCode智库
相关文章:
C语言性能优化:从基础到高级的全面指南
引言 C 语言以其高效、灵活和功能强大而著称,被广泛应用于系统编程、嵌入式开发、游戏开发等领域。然而,要写出高性能的 C 语言代码,需要对 C 语言的特性和底层硬件有深入的了解。本文将详细介绍 C 语言性能优化的背后技术,并通过…...
JS中Symbol (符号)数据类型详解和应用场景
JavaScript中Symbol数据类型详解 Symbol是ES6引入的一种原始数据类型,表示唯一的标识符。它是通过Symbol()函数生成的,每次调用都会返回一个独一无二的值。Symbol值的主要用途是为对象的属性提供唯一标识,以避免属性名冲突。 特点 唯一性 每…...
Go gin框架(详细版)
目录 0. 为什么会有Go 1. 环境搭建 2. 单-请求&&返回-样例 3. RESTful API 3.1 首先什么是RESTful API 3.2 Gin框架支持RESTful API的开发 4. 返回前端代码 go.main index.html 5. 添加静态文件 main.go?改动的地方 index.html?改动的地方 style.css?改…...
Linux系统 —— 进程控制系列 - 进程的等待:wait 与 waitpid
目录 1. 进程的等待 1.1 为什么需要等待 2. 进程等待的方法 1. wait 2. waitpid 3. 获取子进程status 4. 阻塞与非阻塞等待 续接前文: Linux系统 —— 进程控制系列 - 进程的创建与终止 :fork与exit-CSDN博客https://blog.csdn.net/hedhjd/artic…...
blender中合并的模型,在threejs中显示多个mesh;blender多材质烘培成一个材质
描述:在blender中合并的模型导出为glb,在threejs中导入仍显示多个mesh,并不是统一的整体,导致需要整体高亮或者使用DragControls等不能统一控制。 原因:模型有多个材质,在blender中合并的时候,…...
探索多模态大语言模型(MLLMs)的推理能力
探索多模态大语言模型(MLLMs)的推理能力 Multimodal Large Language Models (MLLMs) flyfish 原文:Exploring the Reasoning Abilities of Multimodal Large Language Models (MLLMs): A Comprehensive Survey on Emerging Trends in Mult…...
[Wireshark] 使用Wireshark抓包https数据包并显示为明文、配置SSLKEYLOGFILE变量(附下载链接)
wireshark 下载链接:https://pan.quark.cn/s/eab7f1e963be 提取码:rRAg 链接失效(可能会被官方和谐)可评论或私信我重发 chrome与firefox在访问https网站的时候会将密钥写入这个环境变量SSLKEYLOGFILE中,在wireshark…...
单片机实物成品-007 汽车防盗系统(代码+硬件+论文)
汽车尾气监测系统(温度震动传感器 红外热释电GPS三个指示灯蜂鸣器正常模式防盗模式wifi传输控制送APP源码 ) 把该系统划分为两个不同设计主体,一方面为硬件控制主体,通过C语言来编码实现,以STM32开发板为核心控制器&a…...
redis开发与运维-redis0401-补充-redis流水线与Jedis执行流水线
文章目录 【README】【1】redis流水线Pipeline【1.1】redis流水线概念【1.2】redis流水线性能测试【1.2.1】使用流水线与未使用流水线的性能对比【1.2.2】使用流水线与redis原生批量命令的性能对比【1.2.3】流水线缺点 【1.3】Jedis客户端执行流水线【1.3.1】Jedis客户端执行流…...
windows系统下使用cd命令切换到D盘的方法
windows系统下使用cd命令切换到D盘的方法 系统环境配置 win10系统原装C盘后期自己安装的硬盘D盘 python3.8安装在D盘中 问题说明 winR打开终端,使用 cd d:命令,无法将当前目录切换到D盘 解决方法 方法一:使用下面这条命令 cd /d d:运…...
word参考文献第二行缩进对齐
刚添加完参考文献的格式是这样: ”段落“—>缩进修改、取消孤行控制 就可以变成...
Springboot关于格式化记录
日期格式化 返回前端日期需要格式化 <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.2</version> </dependency>JsonFormat(pattern "yyyy-MM-dd…...
1.business english--build rapport
build rapport with someone 建立融洽关系 Salespeople often try to build rapport with customers to boost sales. user a variety of appropriate questions. answer the question according to your experience. Do you know how to make a good connection with others…...
发明专利与实用新型专利申请过程及自助与代办方式对比
申请专利(发明专利、实用新型专利、外观设计专利)有两种方式:1、自己直接向国家知识产权局申请。2、通过专利代办处申请。以下是对这两种专利类型(发明专利、实用新型专利)申请过程及两种申请方式的详细介绍和对比,参考…...
设计模式-创建型-工厂方法模式
什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是 创建型设计模式之一,目的是通过定义一个用于创建对象的接口,让子类决定实例化哪个类。简而言之,工厂方法模式通过延迟对象的创建过程到子类来…...
如何判断一个学术论文是否具有真正的科研价值?ChatGPT如何提供帮助?
目录 1.创新性与学术贡献的超级加分✔ 2.科研过程中的各个环节—从0到1✔ 3.创新性与理论深度的完美结合✔ 4.论证与写作的清晰性✔ 5.数据整理和文献回顾——效率与精准并存✔ 6.创新性要求辅助✔ 总结 宝子们,学术论文写作的旅程是不是感觉像是走进了迷雾森…...
Linux驱动开发--字符设备驱动开发
一、概述 字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节 流进行读写操作的设备,读写数据是分先后顺序的。比如我们最常见的点灯、按键、 IIC、 SPI, LCD 等等都是字符设备,这些设备的驱动就叫做字符设备驱动。 Linux 应用程序对驱动程…...
Java 网络原理 ①-IO多路复用 || 自定义协议 || XML || JSON
这里是Themberfue 在学习完简单的网络编程后,我们将更加深入网络的学习——HTTP协议、TCP协议、UDP协议、IP协议........... IO多路复用 ✨在上一节基于 TCP 协议 编写应用层代码时,我们通过一个线程处理连接的申请,随后通过多线程或者线程…...
828华为云征文|使用sysbench对Flexus X实例对mysql进行性能测评
目录 一、Flexus X实例概述 1.1?Flexus X实例 1.2?在mysql方面的优势 二、在服务器上安装MySQL 2.1 在宝塔上安装docker 2.2 使用宝塔安装mysql 2.3 准备测试数据库和数据库表 三、安装sysbench并进行性能测试 3.1 使用yum命令sysbench 3.2?运行?sysbench 并进行…...
数据结构:堆
目录 1.堆的概念 2.堆的结构 3.堆的初始化 4.堆的销毁 5.堆的插入 6.堆的删除 7.判断堆是否为空 1.堆的概念 堆的性质: 堆中某个结点的值总是不大于或不小于其父结点的值; 堆总是一棵完全二叉树。 以下堆的结构默认大堆 : 2.堆的结…...
洪水灾害多智能体分布式模拟示例代码
1. 环境定义:支持灾害动态、地理数据和分布式架构 import numpy as np import random import matplotlib.pyplot as plt# 新疆主要城市及邻接关系 XINJIANG_CITIES {Urumqi: [Changji, Shihezi],Changji: [Urumqi, Shihezi, Turpan],Shihezi: [Urumqi, Changji, K…...
基于 Ragflow 搭建知识库-初步实践
基于 Ragflow 搭建知识库-初步实践 一、简介 Ragflow 是一个强大的工具,可用于构建知识库,实现高效的知识检索和查询功能。本文介绍如何利用 Ragflow 搭建知识库,包括环境准备、安装步骤、配置过程以及基本使用方法。 二、环境准备 硬件要…...
Selenium实践总结
1.使用显示等待而不是隐式等待 隐式等待可能会导致不可预测的测试行为,尤其是在动态 Web 应用程序中。显式等待,它允许您 等待特定条件发生后再继续测试,这种方法提供了更多的控制和可靠性。 WebDriverWait wait new WebDriverWait(drive…...
华为麦芒5(安卓6)termux记录 使用ddns-go,alist
下载0.119bate1 安卓5和6版本,不能换源,其他源似乎都用不了,如果root可以直接用面具模块 https://github.com/termux/termux-app/releases/download/v0.119.0-beta.1/termux-app_v0.119.0-beta.1apt-android-5-github-debug_arm64-v8a.apk 安装ssh(非必要) pkg install open…...
Springboot jar包加密加固并进行机器绑定
获取机器码,通过classfinal-fatjar-1.2.1.jar来获取机器码 命令:java -jar classfinal-fatjar-1.2.1.jar -C 对springboot打包的jar进行加密功能 java -jar classfinal-fatjar-1.2.1.jar -file lakers-ljxny-3.0.0.jar -packages com.lygmanager.laker…...
【Microi吾码】开源力量赋能低代码创新,重塑软件开发生态格局
我的个人主页 文章专栏:Microi吾码 一、引言 在当今数字化浪潮汹涌澎湃的时代,软件开发的需求呈现出爆发式增长。企业为了在激烈的市场竞争中脱颖而出,不断寻求创新的解决方案以加速数字化转型。传统的软件开发方式往往面临着开发周期长、技…...
系统思考—冰山模型
“卓越不是因机遇而生,而是智慧的选择与用心的承诺。”—— 亚里士多德 卓越,从来不是一次性行为,而是一种习惯。正如我们在日常辅导中常提醒自己:行为的背后,隐藏着选择的逻辑,而选择的根源,源…...
Java读取InfluxDB数据库的方法
本文介绍基于Java语言,读取InfluxDB数据库的方法,包括读取InfluxDB的所有数据库,以及指定数据库中的measurement、field、tag等。 首先,创建一个Java项目,用于撰写代码。如果大家是基于IDEA来创建项目,则可…...
【mybatis-plus问题集锦系列】在mybatisplus中无法autowired的原因排查及解决
mybatisplus简化了我们做数据操作,大大提升了我们的开发速度,但是今天在做测试的时候,突然报了这么个错误,排查好久才找到解决方案,特此记录下 问题复现 这里的测试方法报错,通过不了测试 org.springf…...
python中Windows系统使用 pywin32 来复制图像到剪贴板,并使用 Selenium 模拟 Ctrl+V 操作
步骤 1:安装必要的库 首先,安装 pywin32 和 selenium: pip install pywin32 selenium 如果使用的是 macOS,可以安装 pyobjc: pip install pyobjc 步骤 2:使用 pywin32 复制图像到剪贴板 在 Windows 系统中…...
uniapp——微信小程序,从客户端会话选择文件
微信小程序选择文件 文章目录 微信小程序选择文件效果图选择文件返回数据格式 API文档: chooseMessageFile 微信小程序读取文件,请查看 效果图 选择文件 /*** description 从客户端会话选择文件* returns {String} 文件路径*/ const chooseFile () &g…...
点亮核心板小灯 STM32U575
将核心板上的运行状态指示灯点亮 任务分析 灯如何点亮 如何看开发板原理图 开发板上的灯硬件组成 原理图 原理图(Schematic Diagram),也称为电路图或电气图,是一种图形表示方法,用于展示电子系统或电路的工作原理和…...
“图书馆服务自动化”:基于SSM框架的图书借阅系统开发
3.1系统的需求分析 需求分析阶段是设计系统功能模块的总方向,可以这样来说,系统的整个的开发流程以及设计进度,基本上都是以需求分析为基本依据的[10]。需求分析阶段可以确定系统的基本功能设计,以及在最后的系统验收阶段…...
顶顶通呼叫中心中间件的三种呼叫方式(mod_cti基于FreeSWITCH)
顶顶通呼叫中心共有三种呼叫方式: 手拨呼叫点击呼叫自动外呼 联系我们 有意向了解呼叫中心中间件的用户,可以点击该链接添加工作人员:https://blog.csdn.net/H4_9Y/article/details/136148229 手拨呼叫 手拨呼叫属于常规的呼叫方式&…...
HCIA笔记9--NAT、ACL与链路聚合
1. ACL ACL: 访问控制列表, Access Control List。 通过定义规则来允许或拒绝流量的通过。 1.1 ACL分类 1.2 配置实例 如图所示,对R2的访问只允许192.168.1.0/24网段。 我们可以配置基本acl来限制 acl 2000 acl number 2000 rule 5 permit source 192.168.1.0 0…...
【笔记】在虚拟机中通过apache2给一个主机上配置多个web服务器
(配置出来的web服务器又叫虚拟主机……) 下载apache2 sudo apt update sudo apt install apache2 (一)ip相同 web端口不同的web服务器 进入 /var/www/html 创建站点一和站点二的目录文件(目录文件名自定义哈&#x…...
“校园健康数据管理”:疫情管控系统的信息收集与分析
3.1可行性分析 通过对系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1 技术可行性 1.硬件可行性分析 校园疫情管控系统系统的硬件要求方面不存在特殊的要求,…...
MySQL 中存储金额数据一般使用什么数据类型
在 MySQL 中存储金额数据时,应该谨慎选择数据类型,以确保数据的精度和安全性。以下是几种常用的数据类型及其适用性: DECIMAL 类型: 描述:DECIMAL 类型是专门为存储精确的小数而设计的。它可以指定小数点前后的数字位数…...
使用 .NET 6 或 .NET 8 上传大文件
如果您正在使用 .NET 6,并且它拒绝上传大文件,那么本文适合您。 我分享了一些处理大文件时需要牢记的建议,以及如何根据我们的需求配置我们的服务,并提供无限制的服务。 本文与 https://blog.csdn.net/hefeng_aspnet/arti…...
帝国cms电脑pc站url跳转到手机站url的方法
本文讲解一下帝国cms电脑网站跳转到手机动态网站和手机静态网站的方法,笔者以古诗词网 www.gushichi.com为例,为大家介绍操作步骤。方法一:帝国pc站跳转到手机静态站 1、假设我们有帝国cms 电脑网站www.XXX.com,手机网站m.XXX.com …...
D类音频应用EMI管理
1、前言 对于EMI,首先需要理解天线。频率和波长之间的关系,如下图所示。 作为有效天线所需的最短长度是λ/4。在空气中,介电常数是1,但是在FR4或玻璃环氧PCB的情况下,介电常数大约4.8。这种效应会导致信号在FR4材…...
【行业发展报告】2024大数据与智能化行业发展浅析
回首 2024,大数据智能化浪潮汹涌。海量数据宛如繁星,在智能算法的苍穹下汇聚、碰撞,释放出洞察市场与用户的强大能量,精准勾勒出商业新航线。我们精心雕琢技术架构,从数据存储的坚固基石到处理分析的高效引擎ÿ…...
闲谭Scala(3)--使用IDEA开发Scala
1. 背景 广阔天地、大有作为的青年,怎么可能仅仅满足于命令行。 高端大气集成开发环境IDEA必须顶上,提高学习、工作效率。 开整。 2. 步骤 2.1 创建工程 打开IDEA,依次File-New-Project…,不好意思我的是中文版:…...
系统压力测试助手——stress-ng
1、背景 在系统性能测试和压力测试中,stress-ng 是一个非常强大的工具,广泛应用于对 Linux 系统进行各种硬件和软件方面的负载测试。它能够模拟多种极端负载情况,帮助开发人员和运维人员检查系统在高负载下的表现,以便发现潜在的…...
FFmpeg推拉流命令
命令简介 它可以将本地的视频/音频流推送到服务器,也可以将服务器上的音视频流拉到本地。 推流命令的命令格式 ffmpeg -re -i [输入文件] -c:v [视频编码器] -c:a [音频编码器] -f [输出格式] [推流地址] 参数解析 -re 表示采用实时模式,以原始速度…...
【Spring】基于注解的Spring容器配置—— @Component及其衍生注解
Spring框架因其灵活性和强大的功能被广泛应用于企业级应用的开发中。Spring提供了一种基于IoC(控制反转)和AOP(面向切面编程)的编程模型,使得开发者能够以更简单和高效的方式管理应用程序的对象及其依赖关系。 在Spri…...
基于统计分析与随机森林的环境条件对生菜生长的影响研究
1.项目背景 随着现代农业的发展,对植物生长过程中环境因素的影响有了越来越多的关注,基于2023年8月3日至2023年9月19日期间记录的70个不同生菜样本的生长数据进行分析,可以更好地理解温度、湿度、pH值和总溶解固体(TDS࿰…...
基于PyQt5的UI界面开发——多界面切换
介绍 最初,因为课设的缘故,我只是想做一个通过按键进行切面切换而已,但是我看网上资料里面仅是语焉不详,让我困惑的很,但后面我通过摸索才发现这件事实在是太简单了,因此我想要记录下来。 本博客将介绍如…...
C语言-结构体内存大小
#include <stdio.h> #include <string.h> struct S1 { char a;//1 int b;//4 char c;//1 }; //分析 默认对齐数 成员对齐数 对齐数(前两个最小值) 最大对齐数 // 8 1 …...
搭建vue项目
一、环境准备 1、安装node node官网:https://nodejs.org/zh-cn 1.1、打开官网,选择“下载”。 1.2、选择版本号,选择系统,根据需要自行选择,上面是命令安装方式,下载是下载安装包。 1.3、检查node安装…...