2022. 4. 21. 20:09ㆍProgramming/JAVA, C++, Go, Rust
- 목차
thread 기반보다 task 기반 programming을 선호하라는 의미는
std::thread를 사용하는 thread 기반 방식 보다
std::async를 사용하는 task 기반 방식을 사용하라는 것
thread 대신 async 사용 시,
1) 세부 사항 제어에서 벗어날 수 있음
prio. load balancing, thread 실행 불가 시 처리를 알아서 수행
2) future를 통해 리턴을 획득 할 수 있음
future를 통해 비동기 실행 function의 return을 받을 수 있음
future 객체
std::future, std::shared_future
3) async는 기본 software thread를 생성하지 않을 수 있음
지정된 함수를 doAsyncWork의 결과가 필요한 thread에서 실행하게 할 수 있음
(fut에 대해 get이나 wait을 하는 thread에서)
C++에서의 thread 의미
1) hardware thread: CPU core 당 지니는 하나 이상의 thread
2) software thread: OS thread/system thread
3) C++ std::thread
thread에 대한 handle로 작용
handle의 null 가능
- 기본생성자로 생성된 경우 (without handler)
- 객체의 이동 후
- join을 통해 다른 thread와 합류한 경우
- detach를 통해 탈착된 경우 (끊어진 경우)
software thread는 제한적 자원
out of pool 경우 std::system_error exception이 발생
task function이 noexcept로 선언되어도 발생
thread를 직접 잘못 사용 시의 문제
thread가 많아지면 context switching의 overhead는 커짐
core간 이동되는 context switching 시 overhead는 더 커짐
TBL flush ? I/D cache flush
최상의 software vs. hardware thread의 ratio는
context switching 비율, software thread가 CPU cache를 얼마나 효과적으로 허용하는가에 의존
이런 detail을 다른 thread로 넘기는 것이 async의 사용 임
auto fut = std::async(doAsyncWrok);
thread를 직접 다루는 것이 적합한 경우
1) Low level 제어 필요 경우
affinity, priority등을 직접 제어해야 하는 경우
이는 std::thread의 handle을 통해 가능
std::future는 이런 기능을 제공하지 않음 (더 high level 임)
2) thread 사용량 최적화 필요 경우
computer 전체에 대한 동작 context는 개발자가 더 잘 알고 있을 가능성이 있기에
직접 제어 하는 것이 load balancing 측면에서 이점을 지닐 수 있음
3) 자체적으로 thread API를 구현해야 하는 경우
thread pool등을 직접 구현해서 성능을 높이고자 하는 경우 등
async의 동작
1) 기본 동작
async | deferred 임
기본 launch policy에서는 f가 비동기적으로 실행될 수도 있고 아닐 수도 있음
auto fut = std::async(f);
이 statement가 이를 호출한 thread에서 실행되는지, 아니면
동시 실행(get이나 wait에서 실행)인지 예측 불가임
auto fut = std::async(f);
fut이 deferred 값을 지닌 stack variant일 수도 있음
이때
while (fut.wait_for(100ms)) { <- 이 동작은 무한 loop
...
}
defer check가 필요
if (fut.wait_for(0s) == std::future_status::deferred) {
} else {
while (fut.wait_for(100ms) != std::future_status::ready) {
...
}
}
2) std::launch::async
다른 thread에서 비동기로 반드시 동작 시켜야 하는 경우
std::async로 하면 동일 thread에서 동작 시켜 반응성 문제를 야기할 수 있음
-> 역시 GUI thread의 반응성 문제가 발생 가능
어느 thread가 반응성이 좋아야 하는 것인지 알 수 없기 때문
이때 std::launch::async를 사용
이는 현재와 다른 thread에서 수행되는 것을 강제함
최신 scheduler는 전역 thread pool을 사용해 over subscription을 막음
work-stealing 알고리즘을 이용해 load를 hardware core로 효과적으로 분배
std::thread를 사용하면
thread 고갈, 과다구독, load balancing등을 직접 처리해야 함
다른 프로세스에서 실행되는 thread들에 대해서도 잘 맞물리게 신경써야 함
단, thread 고갈 문제 발생 가능
3) std::launch::deferred
future의 get, wait 호출 시부터 동기적으로 실행됨
'Programming > JAVA, C++, Go, Rust' 카테고리의 다른 글
C++ set 사용법 (0) | 2022.10.08 |
---|---|
C++ file path (파일 경로) 획득 방법 (0) | 2022.10.04 |
Smart pointers (0) | 2022.04.21 |
Effective Modern C++ (0) | 2022.04.21 |
Universal reference (0) | 2022.04.16 |