You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

std::transform搭配std::execution::par_unseq未生效,如何利用全部CPU核心?

问题:C++20 std::transform并行版本未充分利用CPU核心

用户编写了以下C++20代码,意图通过std::transform结合std::execution::par_unseq执行并行转换以利用16核CPU,但运行后发现并行版本与串行版本的transform操作耗时差异较小,硬件并发数未被充分利用。

代码实现

#include <iostream>
#include <numeric>
#include <vector>
#include <cmath>
#include <execution>
#include <chrono>
using std::cout;
using std::endl;

static auto start_time = std::chrono::high_resolution_clock::now();
// 启动计时器
void tick() {
    
    start_time = std::chrono::high_resolution_clock::now();
}

// 停止计时器并输出耗时(毫秒)
void tock() {
    auto end_time = std::chrono::high_resolution_clock::now();
    auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
    std::cout << "Elapsed time: " << duration_ms << " ms" << std::endl;
}

double compute_p_n(double m, int n) {
    return 0.5 * (1 - std::pow(1 - 2 * m, n));
}

void do_work(auto pol)
{
    const double m = 1e-2;
    const int k = 3e8; 
    std::vector<double> input(k);
    std::vector<double> results(k);

    tick();
    std::iota(input.begin(), input.end(), 1); // 初始化为1、2、3……k
    cout << "initializing with indices: ";
    tock(); 
    
    tick();
    std::transform(pol, input.begin(), input.end(), results.begin(),
                   [m](double n) { return compute_p_n(m, n); }); // 计算p(n)
    cout << "transform: "; 
    tock();
    
}

int main() {
    
    cout << "hw concur: " << std::thread::hardware_concurrency() << endl;

    cout << "parallel: " << endl;
    do_work(std::execution::par_unseq);
    
    cout << endl << "sequential: " << endl;
    do_work(std::execution::seq);


    return 0;
}

编译与运行信息

编译命令:
g++ compute_prob.cpp --std=c++20 && ./a.out

运行结果:

硬件并发数:16
并行版本:
初始化索引耗时:1389 毫秒
transform操作耗时:5303 毫秒

串行版本:
初始化索引耗时:1366 毫秒
transform操作耗时:6576 毫秒

解决方案

  • 启用并行库链接:GCC的并行STL依赖Intel TBB库,默认编译不会自动链接。修改编译命令为:
    g++ compute_prob.cpp --std=c++20 -ltbb && ./a.out
    若系统未安装TBB,需先安装(例如Ubuntu执行sudo apt install libtbb-dev)。

  • 优化任务计算粒度:当前每个compute_p_n的计算量极小,线程调度开销远超并行收益。可以将多个元素的计算合并为单个任务,或增大单次计算的复杂度,让线程有足够的计算量分摊调度成本。

  • 缓解内存带宽瓶颈:k=3e8的两个double类型vector共占用约4.8GB内存,内存带宽可能成为瓶颈限制CPU利用率。可尝试减小k的值,或改用float类型(若精度允许)降低内存占用。

  • 验证并行执行状态:运行时用htop或top工具观察CPU使用率,确认并行版本是否真正启用多核心计算。若编译器未正确启用并行支持,par_unseq会自动退化为串行执行。

  • 优化计算函数性能:std::pow调用存在性能瓶颈,可替换为快速幂实现或近似计算方法,提升单线程计算效率,进而放大并行加速效果。

内容的提问来源于stack exchange,提问作者Bob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 18:54:57