C++代码优化(9)

文章介绍了优化数据存储以减少冗余和提高内存利用率,使用预处理技术如模板元编程,优化多线程调度以减少线程切换开销,以及采用适当的内存管理策略来提升程序性能。其他还包括使用分支预测、选择合适编译器、ProfileGuidedOptimization(PGO)、计算与I/O分离等技术。
摘要由CSDN通过智能技术生成

33. 优化数据存储:减少数据冗余,使用紧凑的数据结构以提高内存利用率。

  优化数据存储可以减少数据冗余,使用紧凑的数据结构以提高内存利用率。这样可以减少内存使用量,从而降低内存访问延迟,提高程序性能。
  不紧凑的数据结构

std::vector<Person> people;
people.push_back({"Alice", 25});
people.push_back({"Bob", 30});
people.push_back({"Charlie", 35});

紧凑的数据结构
std::vector<std::string> names{"Alice", "Bob", "Charlie"};

34. 使用预处理技术:例如模板元编程,将计算放在编译阶段进行,减少运行时开销。

  没什么屁用

35. 优化多线程调度:合理分配线程资源,减少线程切换开销。

  优化多线程调度可以合理分配线程资源,减少线程切换开销,从而提高程序性能。线程切换是指操作系统从一个线程切换到另一个线程的过程,这个过程涉及到上下文切换和内存切换等开销,会导致性能下降。

  以下是一个优化多线程调度的例子:

#include <iostream>
#include <thread>
#include <vector>

void worker(int id) {
    std::cout << "Worker " << id << " started" << std::endl;
    for (int i = 0; i < 100000000; ++i) {
        // do some work
    }
    std::cout << "Worker " << id << " finished" << std::endl;
}

int main() {
    std::vector<std::thread> workers;
    for (int i = 0; i < 4; ++i) {
        workers.emplace_back(worker, i);
    }

    for (auto& worker : workers) {
        worker.join();
    }

    return 0;
}

  在这个例子中,我们创建了4个线程,每个线程都执行一个worker函数,用于模拟一些工作。在主线程中,我们等待所有线程完成,然后输出结束信息。

  如果使用默认线程调度策略,可能会导致线程切换过于频繁,从而降低程序性能。为了优化多线程调度,我们可以尝试以下方法:

  将线程数设置为CPU核心数或少于CPU核心数,以避免过多线程竞争CPU资源。
将线程分配到不同的CPU核心上,以避免线程之间互相干扰,从而减少线程切换开销。
将线程分组,并为每个线程组分配不同的优先级,以确保高优先级的线程能够获得更多的CPU资源,从而减少线程切换开销。
  总之,优化多线程调度可以合理分配线程资源,减少线程切换开销,从而提高程序性能。在实际编程中,需要根据具体的情况选择最优的调度策略。

36. 使用适当的内存管理策略:例如分配器、内存池等,以提高内存分配和释放性能。

37. 利用分支预测:了解处理器的分支预测原理,编写符合预测策略的代码。

38. 选择合适的编译器:不同编译器对代码的优化效果可能不同,选择最适合项目需求的编译器。

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -stdlib=libc++")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2 /EHsc")
endif()

39. 利用Profile Guided Optimization(PGO):使用编译器的PGO特性,根据运行时信息对代码进行优化。

  Profile Guided Optimization(PGO)是一种编译器优化技术,它可以根据程序的运行时信息对代码进行优化,以提高程序性能。
使用PGO优化程序需要分为三个步骤:
  训练阶段:使用测试数据集对程序进行运行,并记录程序的运行时信息,例如函数调用频率、分支跳转情况等。然后,将这些信息保存在一个文件中,以便在后续的编译阶段使用。
  编译阶段:使用编译器的PGO特性对代码进行优化。编译器可以根据训练阶段保存的运行时信息对代码进行优化,例如对频繁调用的函数进行内联、对热点代码进行缓存等。
  运行阶段:使用经过优化的程序对实际数据集进行测试,并验证优化效果。
  举个例子,我们有一个C++程序,需要对一个整数向量进行排序,并输出排序后的结果。为了使用PGO优化程序,我们可以首先使用测试数据集对程序进行运行。训练阶段结束后,我们再次使用编译器进行编译,以便使用PGO特性优化程序。最后,我们再次运行程序,并验证优化效果。
  通过使用PGO优化程序,我们可以根据实际运行时信息对代码进行优化,提高程序性能。

40. 将计算与I/O分离:在多线程环境中,将计算与I/O操作分离,以提高整体性能。

  在多线程环境中,I/O操作通常会成为性能瓶颈。为了提高整体性能,可以将计算与I/O操作分离,让不同的线程分别负责计算和I/O操作,以避免I/O操作对计算的影响。

41. 使用矢量化指令集:例如SSE、AVX等,可以同时处理多个数据,提高计算性能。

42. 尽量减少模板实例化:模板实例化可能导致代码膨胀,影响性能。谨慎使用模板,避免不必要的实例化。

43. 采用延迟初始化:在需要时才进行对象初始化,避免不必要的内存分配和计算开销。

  针对类

44. 利用空间换时间:通过增加内存使用,减少计算开销,例如使用查找表、缓存等。

45. 使用条件表达式替代分支:在某些情况下,使用条件表达式(如a ? b : c)可以减少分支预测错误。

46. 选择最适合的容器:根据应用场景选择最适合的容器,例如使用std::vector替代std::list,以提高内存局部性。

47. 使用内建函数:例如__builtin_popcount等,这些函数通常比手动实现的版本更高效。

48. 使用迭代器而不是下标:对于某些容器(如std::list),使用迭代器访问元素比使用下标更高效。

  在C++中,访问容器中的元素可以使用下标或迭代器。对于某些容器(如std::list),使用迭代器访问元素比使用下标更高效,因为下标操作需要进行较多的指针运算和内存访问,而迭代器则可以避免这些操作。

49. 将对象存储在连续内存中:例如使用std::vector,以提高内存局部性和访问性能。

50. 使用裁剪技术:在处理大量数据时,只处理与结果相关的部分数据,以降低计算复杂度。

51. 尽量减少数据依赖:数据依赖会导致流水线停顿,尽量减少数据依赖以提高处理器利用率。

  数据依赖指的是指令之间的数据依赖关系,即一个指令需要依赖于前面某个指令的结果才能执行。数据依赖会导致流水线停顿,从而降低处理器的利用率,影响程序的执行效率。

52. 使用算法重用:对于相似问题,可以考虑使用已有的优化算法进行调整和重用。

53. 在性能关键部分使用固定大小的容器:这可以避免动态内存分配和容器扩容的开销。

54. 避免过度使用 STL 容器:STL 容器是很方便的,但它们可能不是最快的数据结构。在需要高效性能时,请考虑使用基于数组或链表的数据结构。

55. 使用基于范围的 for 循环:基于范围的 for 循环比传统的 for 循环更快,因为它避免了指针的解引用操作。

  基于范围的for循环是C++11引入的新特性,它可以方便地遍历各种容器和数组,避免了传统的for循环中需要使用指针解引用的操作。这样可以减少指针运算和内存访问,提高程序的执行效率。

  以下是一个使用基于范围的for循环的示例,假设我们需要遍历一个vector中的元素:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用传统的for循环
    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 使用基于范围的for循环
    for (int& i : vec) {
        std::cout << i << " ";
    }
    std::cout << std::endl;

    return 0;
}

  在这个示例中,我们使用传统的for循环和基于范围的for循环分别遍历一个vector中的元素。可以看到,使用基于范围的for循环可以避免指针解引用的操作,代码更简洁,执行效率更高。

  总的来说,基于范围的for循环比传统的for循环更快,因为它避免了指针的解引用操作,可以提高程序的执行效率。在实际开发中,可以根据需要选择合适的循环方式,以提高程序的效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值