KoreanFoodie's Study
[C++ 게임 서버] 1-11. future, promise, packaged_task 본문
[C++ 게임 서버] 1-11. future, promise, packaged_task
핵심 :
1. future, promise, packaged_task 는 단발성 이벤트를 비동기적으로 실행할 때 유용하다.
2. 세 녀석의 차이는 Level of Control 에 달려 있다. future 는 특정 함수의 작업을 맡기고, packaged_task 는 작업을 만든 다음, 쓰레드에 이를 실어 보낸다. 마지막으로, promise 는 작업을 실어 보내면서, 동시에 실어 보내는 함수 내부에서 future 에 넘길 값을 커스텀하게 세팅할 수 있다.
3. '비동기적'인 작업과 '멀티쓰레드' 는 다른 의미이다. 어떤 작업이 비동기적으로 실행된다고 해서, 꼭 멀티쓰레드를 이용할 필요는 없다.
사실 자주 쓰이는 녀석들은 아니지만, 간단한 일회성 이벤트의 경우 future, promise, packaged_task 를 사용하면 복잡하게 lock 과 관련된 사항들을 체크할 필요없이 비동기적인 작업을 효율적으로 수행할 수 있다.
아래 예제 코드를 보면, 이해가 한 번에 될 것이다.
int64 Calculate()
{
int64 sum = 0;
for (int64 i = 0; i < 100'000; ++i)
{
sum += i;
}
return sum;
}
void PromiseWorker(promise<string>&& InPromise)
{
InPromise.set_value("Secret Message");
}
void TaskWorker(packaged_task<int64(void)>&& task)
{
task();
}
int main()
{
// Future
// 실제로 원하는 값을 사용할 때 작업이 진행됨.
// 락을 사용하지 않는 간단한 작업
{
// Future 를 만들 때 3가지 옵션이 있음
// 1. launch::async : 다른 쓰레드를 만들어서 작업을 맡김
// 2. launch::deferred : 동일한 쓰레드 내에서, 실제로 get 을 할 때 값을 계산 (Lazy Evaluation)
// 3. deferred | async : 컴파일러에게 어떤 옵션을 수행할지 맡김
future<int64> f = std::async(launch::async, Calculate);
// Do Something
// 결과물이 이제서야 필요함
int64 sum = f.get();
cout << "Future Sum : " << sum << endl;
}
// Promise
// 미래(std::future) 에 결과물을 반환해거라 약속(std::promise) 해줘~ (계약서)
{
promise<string> promiseRes;
future<string> futureRes = promiseRes.get_future();
thread t(PromiseWorker, std::move(promiseRes));
string message = futureRes.get();
cout << "Promise : " << message << endl;
t.join();
}
// Packaged Task
{
packaged_task<int64(void)> task(Calculate);
future<int64> future = task.get_future();
thread t(TaskWorker, std::move(task));
int64 sum = future.get();
cout << "Packaged Task Sum : " << sum << endl;
t.join();
}
// 결론)
// mutex, condition_variable 을 사용하지 않고 간단한 작업을 맡김
// 특히나, 한 번 발생하는 이벤트에 유용
// 닭잡는데 소잡는 칼을 쓸 필요없다!
// 1) async
// 원하는 함수를 비동기적으로 실행
// 2) promise
// 결과물을 promise 를 통해 future 로 받아줌
// 3) packaged_task
// 원하는 함수의 실행 결과를 packaged_task 를 통해 future 로 받아줌
}
실제로 promise 와 packaged_task 는 현업에서 거의 볼 일이 없다고 한다. 실제로도 future 로 대부분의 케이스를 처리할 수 있을 것으로 보인다 😅
사실 세 녀석의 차이는 Level of Control 에 달려 있다.
future 는 특정 함수의 작업을 맡긴다. 그게 끝이다. 맡기면 그냥 맡긴 일에 대한 결과를 get 을 할 때 확인한다.
packaged_task 는 작업을 만든 다음, 쓰레드에 이를 실어 보낸다. 쓰레드를 직접 만드니까 여러 쓰레드에 이를 넘길 수 있고, 작업을 수행하는 쓰레드를 재활용할 수도 있다.
마지막으로, promise 는 작업을 실어 보내면서, 동시에 실어 보내는 함수 내부에서 future 에 넘길 값을 커스텀하게 세팅할 수 있다. 즉, 작업을 맡기되, 실제 get 을 할때의 값을 작업을 해 주는 함수 내부에서 조작할 수도 있다(물론 값을 받고 나서 조작을 할 수도 있겠지만, 조건문이 필요한 경우에는 해당 함수에서 처리하는 것이 더 깔끔할 것이다).
세 녀석에 대한 차이를 좀 더 자세히 알고 싶으면 이 링크를 참고하자 😉
'Game Dev > Game Server' 카테고리의 다른 글
[C++ 게임 서버] 1-13. CPU 파이프라인 (feat. 코드 재배치) (0) | 2023.07.19 |
---|---|
[C++ 게임 서버] 1-12. 캐시 (Temporal Locality, Spatial Locality) (0) | 2023.07.19 |
[C++ 게임 서버] 1-10. Condition Variable (조건 변수) (0) | 2023.07.14 |
[C++ 게임 서버] 1-9. 이벤트 구현 (+ Handle) (0) | 2023.07.14 |
[C++ 게임 서버] 1-8. Sleep 개념과 구현 (0) | 2023.07.12 |
Comments