🎮
Future
January 07, 2024
Future
동기 vs 비동기
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
#include <future>
int64 Calculate()
{
int64 sum = 0;
for (int32 i = 0 ; i < 100'000 ; i++)
sum += i;
result = sum;
return sum;
}
int main()
{
// 동기(synchronous) 실행
int64 sum = Calculate();
cout << sum << endl;
return 0;
}
- 위 코드는 동기적이다.
- 만약 Calculate가 굉장히 오랜 시간동안 연산하고, 그것을 기다리는 동안 다른 작업을 하고 싶다면?
- 우리가 배운 내용을 토대로 아래와 같이 작성 가능하다.
Thread 이용
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
#include <future>
int64 result;
int64 Calculate()
{
int64 sum = 0;
for (int32 i = 0 ; i < 100'000 ; i++)
sum += i;
result = sum;
return sum;
}
int main()
{
thread t(Caltulate);
//다른 작업 수행
t.join();
cout << result << endl;
return 0;
}
- thread를 생성 후
Calculate()
task를 위임하여 비동기적으로 작동한다.= - 간단한 작업을 하는데도 불구하고, 굳이 쓰레드까지 만들어서 관리하기 귀찮다.
->
std::future
&std::async
를 통해 해결 가능하다.
future
+ async
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
#include <future>
int64 Calculate()
{
int64 sum = 0;
for (int32 i = 0 ; i < 100'000 ; i++)
sum += i;
result = sum;
return sum;
}
int main()
{
// std::future
{
std::future<int64> future = std::async(std::launch::async/*정책*/, Calculate);
// 다른 작업 수행
//10ms 동안 future 상태 관찰
std::future_status status = future.wait_for(10ms);
int64 sum = future.get(); //결과물이 이제서야 필요하다!
}
}
async에는 두가지 policy가 있다.
enum class launch { async = 0x1, deferred = 0x2, }
Options
- deferred
- lazy evaluation : 지연해서 실행하세요 -> 테스트 결과
future.get()
을 호출할 때가 돼서야 쓰레드로 분기되는듯?
- lazy evaluation : 지연해서 실행하세요 -> 테스트 결과
- async
- 별도의 쓰레드를 만들어서 실행하세요
- deferred | async
- 둘 중 알아서 골라주세요
future
+ promise
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
#include <future>
int64 Calculate()
{
int64 sum = 0;
for (int32 i = 0 ; i < 100'000 ; i++)
sum += i;
return sum;
}
void PromiseWorker(std::promise<string>&& promise)
{
promise.set_value("Secret Message");
}
int main()
{
// std::promise
{
// 미래(std::future)에 결과물을 반환해줄거라 약속
std::promise<string> promise;
std::future<string> future = promise.get_future();
thread t(PromiseWorker, std::move(promise));
string message = future.get();
cout << message << endl;
t.join();
}
}
🏳️이 부분은 아직 모던 C++에 대해 배우지 않아 대충 이해만 하고 넘어갔다.
모던 C++ 학습 후 오른값 참조에 대해 복습해야할 것
future
+ packaged_task
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
#include <future>
int64 Calculate()
{
int64 sum = 0;
for (int32 i = 0 ; i < 100'000 ; i++)
sum += i;
return sum;
}
void TaskWorker(std::packaged_task<int64>&& task)
{
task(); //함수를 호출
}
int main()
{
// std::packaged_task
{
std::packaged_task<int64(void)> task(Calculate);
std::future<int64> future = task.get_future();
std::thread t(TaskWorker, std::move(task));
int64 sum = future.get();
cout << sum << endl;
t.join();
}
}
packaged_task
의 타입은 함수타입과 맞춰줘야 한다. ->Calculate()
이기 때문에int64
,void
promise
-future
의 관계와packaged_task
-future
의 관계는 비슷하다.
결론
- mutex, condition_variable을 사용하지 않고 단순한 기능을 처리할 수 있는 방법에 대해 알아보았다.
- 1회성 이벤트에 유용하다.
- async : 원하는 함수를 비동기적으로 실행
- promise : 결과물을 promise를 통해 future로 받아줌
- packaged_task : 원하는 함수의 실행 결과를 packaged_task를 통해 future로 받아줌