
std::execution::par 和 std::execution::par_unseq 的实际区别在哪?
两者都启用多线程并行,但 std::execution::par_unseq 还允许编译器对同一迭代内操作做向量化(如 SIMD),而 std::execution::par 仅保证线程级并行,不承诺向量化。这意味着:若你的算法逻辑可安全重排(比如累加、求最大值、transform),std::execution::par_unseq 通常更快;但若涉及顺序敏感的副作用(如修改共享计数器、依赖前序迭代结果),必须用 std::execution::par,否则行为未定义。
常见误用:对含 std::cout 或 push_back() 到同一容器的操作盲目加 par_unseq —— 输出乱序、数据竞争风险极高。
哪些标准算法真正支持并行执行策略?
不是所有 函数都支持 std::execution 策略。C++17 明确要求支持并行化的有:
-
std::sort、std::stable_sort -
std::for_each、std::for_each_n -
std::reduce、std::transform_reduce -
std::exclusive_scan、std::inclusive_scan -
std::transform、std::copy、std::fill -
std::find、std::find_if、std::search
注意:std::unique、std::partition、std::nth_element 等虽在标准中“鼓励实现支持”,但实际是否并行取决于 STL 实现(如 libstdc++ 12+ 和 libc++ 14+ 才逐步补全)。调用前务必查文档或实测 std::chrono 对比耗时。
立即学习“C++免费学习笔记(深入)”;
为什么开了 std::execution::par 反而更慢?
并行开销(线程创建/同步/任务划分)远超计算本身时,加速比为负。典型场景包括:
- 输入规模太小(如
std::vector只有几百个元素) - 每项操作极轻量(如
[](int x) { return x * 2; }) - 迭代器非随机访问(如
std::list上用std::for_each)—— 大部分 STL 实现会退化为串行 - 内存带宽瓶颈(如大量 cache-unfriendly 的随机读写)
建议:对 N 的整型数组,先用串行;超过后才试并行,并用 std::chrono::high_resolution_clock
实测。别依赖理论加速比。
如何正确传递执行策略并避免编译错误?
必须显式传入策略对象作为**第一个参数**,且头文件需包含 。常见错误写法:
#include#include std::vector
v(100000, 1); // ❌ 错误:策略位置不对,或漏掉 std::sort(v.begin(), v.end(), std::execution::par); // ✅ 正确:策略是首个参数,且迭代器类型要匹配 std::sort(std::execution::par, v.begin(), v.end());
// ✅ transform 示例(注意输出迭代器不能和输入重叠,除非用 par_unseq + 无副作用) std::vector
out(v.size()); std::transform(std::execution::par_unseq, v.begin(), v.end(), out.begin(), [](int x) { return x * x; });
关键点:策略类型是函数调用的**重载决议依据**,编译器靠它选择并行版本重载。漏传、错位、或用在不支持的算法上,都会 fallback 到串行版本(无声失败),而非报错。
真正容易被忽略的是:并行算法要求迭代器满足 RandomAccessIterator,且谓词/操作必须是无状态、无外部依赖、无副作用(尤其对 par_unseq)。哪怕一个 lambda 捕获了局部 std::mutex,就已违反前提。











