C++ Execution Policy | "실행 정책" 가이드
이 글의 핵심
C++ Execution Policy에 대해 정리한 개발 블로그 글입니다. #include <algorithm> #include <execution> #include <vector>
Execution Policy란?
알고리즘 실행 방식 (C++17)
#include <algorithm>
#include <execution>
#include <vector>
std::vector<int> v = {3, 1, 4, 1, 5};
// 순차
std::sort(std::execution::seq, v.begin(), v.end());
// 병렬
std::sort(std::execution::par, v.begin(), v.end());
// 병렬 + 벡터화
std::sort(std::execution::par_unseq, v.begin(), v.end());
실행 정책 종류
#include <execution>
// sequenced_policy: 순차
std::execution::seq
// parallel_policy: 병렬
std::execution::par
// parallel_unsequenced_policy: 병렬 + 벡터화
std::execution::par_unseq
// unsequenced_policy: 벡터화 (C++20)
std::execution::unseq
실전 예시
예시 1: 병렬 정렬
#include <algorithm>
#include <execution>
#include <vector>
#include <chrono>
void benchmark() {
std::vector<int> data(10000000);
std::generate(data.begin(), data.end(), std::rand);
// 순차
auto v1 = data;
auto start1 = std::chrono::steady_clock::now();
std::sort(std::execution::seq, v1.begin(), v1.end());
auto end1 = std::chrono::steady_clock::now();
// 병렬
auto v2 = data;
auto start2 = std::chrono::steady_clock::now();
std::sort(std::execution::par, v2.begin(), v2.end());
auto end2 = std::chrono::steady_clock::now();
auto time1 = std::chrono::duration_cast<std::chrono::milliseconds>(end1 - start1);
auto time2 = std::chrono::duration_cast<std::chrono::milliseconds>(end2 - start2);
std::cout << "순차: " << time1.count() << "ms" << std::endl;
std::cout << "병렬: " << time2.count() << "ms" << std::endl;
}
예시 2: 병렬 변환
#include <algorithm>
#include <execution>
int main() {
std::vector<int> v(1000000);
std::iota(v.begin(), v.end(), 1);
// 병렬 변환
std::transform(std::execution::par, v.begin(), v.end(), v.begin(),
{ return x * x; });
}
예시 3: 병렬 집계
#include <numeric>
#include <execution>
int main() {
std::vector<int> v(10000000, 1);
// 병렬 reduce
int sum = std::reduce(std::execution::par, v.begin(), v.end(), 0);
std::cout << "합: " << sum << std::endl;
}
예시 4: 조건부 병렬
#include <algorithm>
#include <execution>
template<typename T>
void conditionalSort(std::vector<T>& v, bool parallel = true) {
if (parallel && v.size() > 10000) {
std::sort(std::execution::par, v.begin(), v.end());
} else {
std::sort(v.begin(), v.end());
}
}
정책 선택
// seq: 순차 (기본)
// - 단일 스레드
// - 예측 가능
// par: 병렬
// - 멀티 스레드
// - 데이터 레이스 주의
// par_unseq: 병렬 + 벡터화
// - SIMD + 멀티 스레드
// - 동기화 불가
자주 발생하는 문제
문제 1: 데이터 레이스
int counter = 0;
std::vector<int> v(1000);
// ❌ 데이터 레이스
std::for_each(std::execution::par, v.begin(), v.end(), [&](int x) {
++counter; // 레이스
});
// ✅ atomic
std::atomic<int> counter{0};
std::for_each(std::execution::par, v.begin(), v.end(), [&](int x) {
++counter;
});
문제 2: 동기화
std::mutex mtx;
// ❌ par_unseq에서 뮤텍스
std::for_each(std::execution::par_unseq, v.begin(), v.end(), [&](int x) {
std::lock_guard lock{mtx}; // 정의되지 않은 동작
// ...
});
// ✅ par에서 뮤텍스
std::for_each(std::execution::par, v.begin(), v.end(), [&](int x) {
std::lock_guard lock{mtx};
// ...
});
문제 3: 오버헤드
std::vector<int> small(100);
// ❌ 작은 데이터에 병렬
std::sort(std::execution::par, small.begin(), small.end());
// 오버헤드 > 이득
// ✅ 큰 데이터에 병렬
std::vector<int> large(10000000);
std::sort(std::execution::par, large.begin(), large.end());
문제 4: 예외
// 병렬 실행 중 예외
try {
std::for_each(std::execution::par, v.begin(), v.end(), {
if (x < 0) {
throw std::runtime_error("음수");
}
});
} catch (...) {
// 여러 예외 가능
// std::terminate() 호출 가능
}
지원 알고리즘
// 대부분의 STL 알고리즘 지원
std::sort(policy, begin, end)
std::transform(policy, begin, end, out, func)
std::for_each(policy, begin, end, func)
std::reduce(policy, begin, end, init)
std::find(policy, begin, end, value)
// ...
FAQ
Q1: Execution Policy?
A: 알고리즘 실행 방식 (C++17).
Q2: 종류?
A: seq, par, par_unseq.
Q3: 병렬 조건?
A:
- 큰 데이터
- 독립적 연산
- 데이터 레이스 없음
Q4: 동기화?
A: par_unseq 불가. par 가능.
Q5: 성능?
A: 큰 데이터에서 효과.
Q6: 학습 리소스는?
A:
- “C++17 The Complete Guide”
- “C++ Concurrency in Action”
- cppreference.com
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ Parallel Algorithms | “병렬 알고리즘” 가이드
- C++ path | “경로 처리” 가이드
- C++ Policy-Based Design | “정책 기반 설계” 가이드
관련 글
- C++ Parallel Algorithms |
- C++ any |
- 모던 C++ (C++11~C++20) 핵심 문법 치트시트 | 현업에서 자주 쓰는 한눈에 보기
- C++ CTAD |
- C++ string vs string_view |