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智库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/946450.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

unity学习4:git和SVN的使用差别

目录 1 svn 1.1 操作逻辑 1.2 对应工具 1.3 SVN避免冲突的好习惯 2 git 2.1 git的基础操作逻辑 2.1.1 commit时&#xff0c;提交文件之外的其他文件需要pull 2.1.2 commit时&#xff0c;发现要提交的本地文件和服务器的文件冲突了 2.1.3 pull 时 2.2 对应工具 2.3 …

2024 年博客总结

2024年 我做了个Hexo博客 &#xff0c;博客地址为&#xff1a;https://blog.mybatis.io。 2024 年发布的文章 一共发布了 31 篇博客&#xff0c;平均一个月 2.6 篇。 Ollama 导入自定义模型 阅读数/评论数: 7433/5Spring AI 使用本地 Ollama Embeddings 阅读数/评论数: 5311…

Python中PDF转Word的技术

Python PDF转Word技术概述 在日常办公和数据处理中&#xff0c;经常需要将PDF文档转换为Word文档&#xff0c;以便进行编辑、修改或格式调整。Python作为一种强大的编程语言&#xff0c;提供了多种库和工具来实现这一功能。以下是对Python中PDF转Word技术的详细介绍。 一、技…

vue3+ts+element-plus 表单el-form取消回车默认提交

问题描述&#xff1a;在表单el-form中的el-input中按回车后&#xff0c;页面会刷新&#xff0c;url也会改变&#xff0c; 回车前&#xff1a; 回车后&#xff1a; 相关代码&#xff1a; 解决方法1&#xff1a;在 el-form 上阻止默认的 submit 事件&#xff0c;增加 submit.pre…

【数据结构05】排序

系列文章目录 【数据结构05】排序 . 【算法思想04】二分查找 文章目录 系列文章目录[toc] 1. 基本思想与实现1.1 插入类排序1.1.1 直接插入排序&#xff08;*&#xff09;1.1.2 折半插入排序1.1.3 希尔排序&#xff08;*&#xff09; 1.2 交换类排序1.2.1 冒泡排序&#xff08…

QT----------文件系统操作和文件读写

一、输入输出设备类 功能&#xff1a; Qt 提供了一系列的输入输出设备类&#xff0c;用于处理不同类型的 I/O 操作&#xff0c;如文件、网络等。 二、文件读写操作类 QFile 类&#xff1a; 提供了对文件的读写操作&#xff0c;可以打开、读取、写入和关闭文件。示例&#x…

Qt自定义步骤引导按钮

1. 步骤引导按钮 实际在开发项目过程中&#xff0c;由一些流程比较繁琐&#xff0c;为了给客户更好的交互体验&#xff0c;往往需要使用step1->step2这种引导对话框或者引导按钮来引导用户一步步进行设置&#xff1b;话不多说&#xff0c;先上效果 2. 实现原理 实现起来…

《Java核心技术II》流中的filter、map和flatMap方法

filter、map和flatMap方法 filter filter通过转换产生过滤后的新流,将字符串流转化为只包含长单词的另一个流。 List words ...; Stream longWords words.stream().filter(w->w.length()>12) filter类型是Predicate(谓词&#xff0c;表示动作)类型对象&#xff0c…

Junit4单元测试快速上手

文章目录 POM依赖引入业务层测试代码Web层测试代码生成测试类文件 在工作中我用的最多的单元测试框架是Junit4。通常在写DAO、Service、Web层代码的时候都会进行单元测试&#xff0c;方便后续编码&#xff0c;前端甩锅。 POM依赖引入 <dependency><groupId>org.spr…

FPGA自学之路:到底有多崎岖?

FPGA&#xff0c;即现场可编程门阵列&#xff0c;被誉为硬件世界的“瑞士军刀”&#xff0c;其灵活性和可编程性让无数开发者为之倾倒。但谈及FPGA的学习难度&#xff0c;不少人望而却步。那么&#xff0c;FPGA自学之路到底有多崎岖呢&#xff1f; 几座大山那么高&#xff1f;…

【Leecode】Leecode刷题之路第97天之交错字符串

题目出处 97-交错字符串-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 97-交错字符串-官方解法 方法1&#xff1a;动态规划 思路&#xff1a; class Solution {public boolean isInte…

【微服务】【Sentinel】认识Sentinel

文章目录 1. 雪崩问题2. 解决方案3. 服务保护技术对比4. 安装 Sentinel4.1 启动控制台4.2 客户端接入控制台 参考资料: 1. 雪崩问题 微服务调用链路中的某个服务故障&#xff0c;引起整个链路中的所有微服务都不可用&#xff0c;这就是雪崩。动图演示&#xff1a; 在微服务系统…

使用 Three.js 创建几何体粒子效果

今天,带大家一起看下如何将几何体由粒子组成的效果。 通常情况下&#xff0c;Three.js 中的几何体材质会为每个面赋予一种颜色&#xff0c;这样的结果比较常见&#xff0c;如下图所示&#xff1a; 然而&#xff0c;通过将几何体由粒子组成&#xff0c;我们可以实现更加酷炫和…

shell指令

终端输入一个C源文件名&#xff08;.c结尾&#xff09;判断文件是否有内容&#xff0c;如果没有内容删除文件&#xff0c;如果有内容编译并执行改文件。 终端输入两个文件名&#xff0c;判断那个时间戳更新

使用ONVIF操纵大华摄像头

使用1台大华网络相机&#xff0c;DH-IPC-HFW3237M-I2&#xff0c;6毫米镜头&#xff0c;2百万像素&#xff0c;但是网口是百兆的。 大华的SDK感觉好难用。 写完了data matrix识别的0.1版本后&#xff0c;进行相机部分改进。 老规矩&#xff0c;先用python快速原型。 会出现一个…

Pandas-数据分组

文章目录 一. 分组聚合1. 分组聚合过程2. Pandas,Numpy内置的聚合方法3. 聚合函数① 使用Numpy库的mean函数② 自定义函数Ⅰ. 一个参数Ⅱ. 多个参数 ③ agg和 aggregateⅠ. 传入一个函数Ⅱ. 同时传入多个函数Ⅲ. 向agg/aggregate中传入字典 二. 分组转换1. 使用transform分组计…

云计算课程报告实验-WordCount算法实验 过程记录

内容描述 本实验指导书通过在华为鲲鹏上&#xff0c;编译运行WordCount程序。完成实验操作后&#xff0c;读者会掌握简单的程序编写&#xff0c;如WordCount中的getWords、countWords、treeMerge。 实验环境 华为鲲鹏云主机、openEuler 20.03操作系统&#xff1b;安装mpich-3…

【paddle】初次尝试

张量 张量是 paddlepaddle&#xff0c; torch&#xff0c; tensorflow 等 python 主流机器学习包中唯一通货变量&#xff0c;因此应当了解其基本的功能。 张量 paddle.Tensor 与 numpy.array 的转化 import paddle as paddle import matplotlib.pyplot as plt apaddle.to_t…

Frontend - 分页(针对 python / Django )

目录 一、同个文件内&#xff08;方式一&#xff09; 1. 前端 html 2. 定义分页界面 3. 获取分页数据 4.后端根据前端分页需求&#xff0c;整理分页数据 5.显示情况 6. JsonResponse 相关知识 二、不同文件内依旧有效&#xff08;方式二&#xff0c;更优化&#xff09;…

骑行解压:身心的奇妙之旅,VELO Angel Revo坐垫

在快节奏的都市生活中&#xff0c;骑行不仅是一种健康的生活方式&#xff0c;更是一种心灵的释放。从心理生理学的角度来看&#xff0c;骑行能够促使身体分泌内啡肽&#xff0c;带来愉悦感&#xff0c;同时&#xff0c;它还能转移注意力&#xff0c;缓解焦虑。在这场身心的奇妙…