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 语言性能优化的背后技术,并通过…...

常用的公共 NTP(网络时间协议)服务器
公共 NTP 服务列表 以下是一些常用的公共 NTP(网络时间协议)服务器,供您参考: 中国地区公共 NTP 服务器 国家授时中心 NTP 服务器:ntp.ntsc.ac.cn中国 NTP 快速授时服务:cn.ntp.org.cn阿里云公共 NTP 服务…...

Kafka中的Topic和Partition有什么关系?
大家好,我是锋哥。今天分享关于【Kafka中的Topic和Partition有什么关系?】面试题。希望对大家有帮助; Kafka中的Topic和Partition有什么关系? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Apache Kafka 中&#…...

Unity 使用UGUI制作卷轴开启关闭效果
视频效果 代码 using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; using DG.Tweening.Core; using DG.Tweening.Plugins.Options;public class JuanZhou : MonoBehaviour {[SerializeField]private …...

MarkDown怎么转pdf;Mark Text怎么使用;
MarkDown怎么转pdf 目录 MarkDown怎么转pdf先用CSDN进行编辑,能双向看版式;标题最后直接导出pdfMark Text怎么使用一、界面介绍二、基本操作三、视图模式四、其他功能先用CSDN进行编辑,能双向看版式; 标题最后直接导出pdf Mark Text怎么使用 Mark Text是一款简洁的开源Mar…...

整合版canal ha搭建--基于1.1.4版本
开启MySql Binlog(1)修改MySql配置文件(2)重启MySql服务,查看配置是否生效(3)配置起效果后,创建canal用户,并赋予权限安装canal-admin(1)解压 canal.admin-1…...

QGIS移动图元功能
有时需要在QGIS里面移动一些矢量图层,比如图层的地理配准,网上搜了一些资料没有查看,后来仔细找了下,在编辑-编辑几何图形-移动要素里面,可以移动图层。 注意:移动前先要选择上要移动的图层,之…...

【模电刷题复习--填空】
如有错误,欢迎各位大佬在评论区批评指正 模电刷题 一、填空题1.本征半导体中,若掺入微量的__五__价元素,则形成___n___型半导体,其多数载流子是自由电子,若掺入微量的__三__价元素,则形成__p__型半导体。其…...

shardingsphere-jdbc-core-spring-boot-starter的性能问题(理论)
hardingSphere-JDBC-core-spring-boot-starter 是 ShardingSphere 提供的与 Spring Boot 集成的模块,用于实现数据库的分库分表等功能。在性能方面,它既有优势也存在一定的挑战,以下是具体分析: 优势方面 数据分片提升查询性能 通…...

Java Map 集合详解:基础用法、常见实现类与高频面试题解析
在 Java 集合框架中,Map 是用于存储键值对(Key-Value)的重要接口,广泛应用于开发中的各种场景。本文将详细讲解 Map 的基础概念、常见实现类及其特性,并结合代码示例和高频面试问题,帮助你深入理解 Map 的用…...

一款基于.Net方便、快捷的数据库文档查询、生成工具
项目介绍 SmartSQL 是一款方便、快捷的数据库文档查询、导出工具!从最初仅支持SqlServer数据库、CHM文档格式开始,通过不断地探索开发、集思广益和不断改进,又陆续支持Word、Excel、PDF、Html、Xml、Json、MarkDown等文档格式的导出。同时又…...

Linux平台下实现的小程序-进度条
目录 1.换行、回车概念 2.缓冲区 2.1缓冲区 2.2强制刷新 3.进度条程序 Makefile文件 ProgressBar.h ProgressBar.c Main.c 执行结果 1.换行、回车概念 /n:换行回车(\r:回车) 2.缓冲区 如下图在vim编辑器中的命令模式下…...

Ubuntu 22.04.5 修改IP
Ubuntu22.04.5使用的是netplan管理网络,因此需要在文件夹/etc/netplan下的01-network-manager-all.yaml中修改,需要权限,使用sudo vim或者其他编辑器,修改后的内容如下: # Let NetworkManager manage all devices on …...

解决virtualbox出现开启DHCP之后ubuntu虚拟机之后IP重复的问题
找遍了国内论坛,没一个能解决该问题的,所以我自己写个文章吧,真讨厌那些只会搬运的,污染国内论坛环境,搜一个问题,千篇一律。 问题 操作系统版本为"Ubuntu 24.04 LTS" lennytest1:~$ cat /etc…...

Java开发工具-Jar命令
Java开发工具-Jar 1、jar命令全平台使用 2、jar命令的作用 为类和资源创建存档,并从存档中操作或恢复单个类或资源 3、摘要 jar [OPTION …] [ [–release VERSION] [-C dir] files] … 4、jar命令描述 jar命令通常作为用于压缩与解压的工具,基于ZIP或Z…...

UE5通过蓝图节点控制材质参数
通过蓝图节点控制材质的参数 蓝图节点 在材质上设置标量值 和 在材质上设置向量参数值 Set Scalar Parameter Value on Materials Set Vector Parameter Value on Materials 这两个蓝图节点都可以在蓝图中,控制材质的参数值和向量值...

敖行客年终总结-AT Work 1.0发布
2024年就要过去了,看看敖行客这一年都干了些啥? 敖行客团队通过整整一年的努力,正式推出了AT Work 1.0订阅版,这也标志着AT Work即将正式和C端的小伙伴见面了。 AT Work 是什么? 长期以来,软件研发成本、…...

线程锁和协程锁的区别
转自:chatgpt 1.bthread_mutex_t bthread_mutex_t 是 brpc 框架提供的一种互斥锁,专门为 bthread(轻量级线程) 设计,具有以下特点: 适用于 bthread 调度模型: bthread_mutex_t 是为 brpc 中的…...

手机租赁平台开发助力智能设备租赁新模式
内容概要 手机租赁平台开发,简单说就是让你用得起高大上的智能设备,不管是最新款的手机、平板,还是那些炫酷的智能耳机,这个平台应有尽有。想要体验但又不希望花大钱?那你就找对地方了!通过灵活的租赁方案…...

掌握大数据处理利器:Flink 知识点全面总结【上】
1.Flink的特点 Apache Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行状态计算。 Flink主要特点如下: 高吞吐和低延迟。每秒处理数百万个事件,毫秒级延迟。结果的准确性。Flink提供了事件时间(event--time)和处理时间(proces…...

人工智能知识分享第四天-线性回归
线性回归 线性回归介绍 线性回归概念 线性回归(Linear regression)是利用 回归方程(函数) 对 一个或多个自变量(特征值)和因变量(目标值)之间 关系进行建模的一种分析方式。 注意事项: 1 为什么叫线性模型?因为求解的w,都是w的零次幂&am…...

Appium 2.0:移动自动化测试的革新之旅
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 在移动应用开发的领域中,Appium 作为一款强大的自动化测试工具…...

牛客网最新1129道 Java 面试题及答案整理
前言 面试,跳槽,每天都在发生,而对程序员来说"金三银四"更是面试和跳槽的高峰期,跳槽,更是很常见的,对于每个人来说,跳槽的意义也各不相同,可能是一个人更向往一个更大的…...

Swift Combine 学习(六):自定义 Publisher 和 Subscriber
Swift Combine 学习(一):Combine 初印象Swift Combine 学习(二):发布者 PublisherSwift Combine 学习(三):Subscription和 SubscriberSwift Combine 学习(四&…...

Vue-router知识点汇总
import Vue from vue import Router from vue-router Vue.use(Router) import Layout from /layout export const constantRoutes [{path: /forgetpsd,name: forgetPsd,// 命名路由 ,跳转<router-link :to"{ name: forgetPsdr, params: { userId: 123 }}&q…...

java AQS
什么是AQS AQS(AbstractQueuedSynchronizer,抽象队列同步器)是 Java 中并发控制的一种机制,位于 java.util.concurrent.locks 包下,它为构建锁、信号量等同步工具提供了一个框架。AQS 通过 队列 来管理多个线程之间的…...

L25.【LeetCode笔记】 三步问题的四种解法(含矩阵精彩解法!)
目录 1.题目 2.三种常规解法 方法1:递归做 编辑 方法2:改用循环做 初写的代码 提交结果 分析 修改后的代码 提交结果 for循环的其他写法 提交结果 方法3:循环数组 提交结果 3.方法4:矩阵 算法 代码实践 1.先计算矩阵n次方 2.后将矩阵n次方嵌入递推式中 提…...

sdut-C语言实验-合数分解
sdut-C语言实验-合数分解 分数 12 全屏浏览 切换布局 作者 马新娟 单位 山东理工大学 合数是指在大于1的整数中,除了1和本身外,还能被其他数整除的数。例如,4、6、8、9、10等都是合数。把一个合数分解成若干个质因数乘积的形式(即求质因…...

深入理解 pytest Fixture 方法及其应用
在 Python 自动化测试领域,pytest 是当之无愧的王者。提到 pytest,不得不说它的一大核心功能——Fixture。Fixture 的强大,让复杂的测试流程变得井井有条,让测试代码更加灵活和可复用。 那么,pytest 的 Fixture 究竟是…...

在Linux上获取MS(如Media Server)中的RTP流并录制为双轨PCM格式的WAV文件
在Linux上获取MS(如Media Server)中的RTP流并录制为双轨PCM格式的WAV文件 一、RTP流与WAV文件格式二、实现步骤三、伪代码示例四、C语言示例代码五、关键点说明六、总结在Linux操作系统上,从媒体服务器(如Media Server,简称MS)获取RTP(Real-time Transport Protocol)流…...