C++11之std::async使用介绍
在C++11中有個async異步函數,其聲明如下:
template <class Fn, class... Args> future<typename result_of<Fn(Args...)>::type>async (launch policy, Fn&& fn, Args&&... args);該模板函數 async 異步地運行函數 fn 并返回最終將保存該函數調用結果的 std::future 中,其中policy策略有以下三種:
// 異步啟動的策略 enum class launch { // 異步啟動,在調用std::async()時創建一個新的線程以異步調用函數,并返回future對象;async = 0x1,// 延遲啟動,在調用std::async()時不創建線程,直到調用了future對象的get()或wait()方法時,才創建線程; deferred = 0x2, // 自動,函數在某一時刻自動選擇策略,這取決于系統和庫的實現,通常是優化系統中當前并發的可用性 any = async | deferred, sync = deferred };- 參數 fn 是要調用的可調用 (Callable) 對象
- 參數args 是傳遞給 f 的參數
異步調用函數可以大大提高程序運行的效率,驗證如下:
輔助函數和聲明
這個是驗證程序的通用代碼:
#include <iostream> // std::cout #include <thread> // std::thread #include <chrono> #include <mutex> #include <memory> #include <functional> #include <future>using namespace std;typedef std::chrono::steady_clock STEADY_CLOCK; typedef std::chrono::steady_clock::time_point TIME_POINT;void print_diff_time(const TIME_POINT& t1, const TIME_POINT& t2) {std::chrono::duration<double, std::milli> dTimeSpan = std::chrono::duration<double,std::milli>(t2-t1);std::cout << "time span : " << dTimeSpan.count() << "ms\n"; }原始程序
下面演示的是,最原始的程序計算代碼,關鍵代碼如下:
//計算A函數 int calculateA() {//延遲1msthis_thread::sleep_for(std::chrono::milliseconds(1));return 1; }//計算B函數 int calculateB() {//延遲2msthis_thread::sleep_for(std::chrono::milliseconds(2));return 2; }//計算C函數 int calculateC() {//延遲3msthis_thread::sleep_for(std::chrono::milliseconds(3));return 3; }//統計三者的和 void test_common_time() {TIME_POINT t1 = STEADY_CLOCK::now();int c = calculateA() + (calculateB() + calculateC());TIME_POINT t2 = STEADY_CLOCK::now();cout << "test_common_time result is :" << c << " ";print_diff_time(t1, t2); }?運行結果:
test_common_time result is :6 time span : 6.55506ms多線程計算
沒有引入多線程計算,程序計算時間達6.5ms,相對效率不高,下面演示多線程計算,代碼如下:
//防止數據競爭 std::mutex g_mtu;void calA(int& sum) {this_thread::sleep_for(std::chrono::milliseconds(1));//多線程加鎖保護lock_guard<mutex> lk(g_mtu);sum += 1; }void calB(int& sum) {this_thread::sleep_for(std::chrono::milliseconds(2));lock_guard<mutex> lk(g_mtu);sum += 2; }void calC(int& sum) {this_thread::sleep_for(std::chrono::milliseconds(3));lock_guard<mutex> lk(g_mtu);sum += 3; }//case2 void test_threads_time() {int sum = 0;TIME_POINT t11 = STEADY_CLOCK::now();//啟動三個線程,進行運算thread t1(calA, ref(sum));thread t2(calB, ref(sum)); thread t3(calC, ref(sum)); //等待計算完成t1.join();t2.join();t3.join();//計算完成TIME_POINT t22 = STEADY_CLOCK::now();cout << "test_threads_time result is :" << sum << " ";print_diff_time(t11, t22);}運行結果:
test_threads_time result is :6 time span : 3.57699ms程序計算時間將近減少了一半,效率提高了很多,但是程序引入了鎖機制,程序的實現相對復雜了。
異步調用
在C++11中引入了async異步調用函數,其封裝了異步(多線程)實現的復雜過程,將計算結果保存在future<>中,通過get()獲取每個對象的最終結果。代碼如下:
//case3 void test_feture_time() {int sum = 0;TIME_POINT t11 = STEADY_CLOCK::now();//異步調用future<int> f1 = std::async(calculateA);future<int> f2 = std::async(calculateB);future<int> f3 = std::async(calculateC);//get()函數會阻塞,直到結果返回sum = f1.get() + f2.get() + f3.get();TIME_POINT t22 = STEADY_CLOCK::now();cout << "test_feture_time result is :" << sum << " ";print_diff_time(t11, t22); }運行結果:
test_future_time result is :6 time span : 3.76372ms相比多線程版本的計算過程,async異步調用整個程序更加簡潔,沒有明顯引入線程,鎖,緩沖區等概念。又比如:
std::future<bool> asyncFuncCall = std::async(std::launch::async, func, args...);// 如果結果還未返回,那么就等待while(asyncFuncCall.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready) {// 做其它的事}總結
async異步調用函數通過啟動一個新線程或者復用一個它認為合適的已有線程,async是語義上的并發即可,并關心具體的調用策略。
”簡單性”是async/future設計中最重視的一個方面;future一般也可以和線程一起使用,不過不要使用async()來啟動類似I/O操作,操作互斥體(mutex),多任務交互操作等復雜任務。async()背后的理念和range-for statement很類似:簡單事兒簡單做,把復雜的事情留給一般的通用機制來搞定。
原文鏈接:https://blog.csdn.net/c_base_jin/article/details/79506347
總結
以上是生活随笔為你收集整理的C++11之std::async使用介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 任天堂公布 3 月马里奥日活动细节:推出
- 下一篇: C++11使用互斥量保护共享数据