1. 程式人生 > 程式設計 >c++11多執行緒程式設計之std::async的介紹與例項

c++11多執行緒程式設計之std::async的介紹與例項

本節討論下在C++11中怎樣使用std::async來執行非同步task。

C++11中引入了std::async

什麼是std::async

std::async()是一個接受回撥(函式或函式物件)作為引數的函式模板,並有可能非同步執行它們.

template<class Fn,class... Args>
future<typename result_of<Fn(Args...)>::type> async(launch policy,Fn&& fn,Args&&...args);

std::async返回一個 std::future<T>,它儲存由 std::async()執行的函式物件返回的值。

函式期望的引數可以作為函式指標引數後面的引數傳遞給std::async()。

std::async中的第一個引數是啟動策略,它控制std::async的非同步行為,我們可以用三種不同的啟動策略來建立std::async

·std::launch::async

保證非同步行為,即傳遞函式將在單獨的執行緒中執行

·std::launch::deferred

當其他執行緒呼叫get()來訪問共享狀態時,將呼叫非非同步行為

·std::launch::async | std::launch::deferred

預設行為。有了這個啟動策略,它可以非同步執行或不執行,這取決於系統的負載,但我們無法控制它。

如果我們不指定一個啟動策略,其行為將類似於std::launch::async | std::launch::deferred

本節我們將使用std::launch::async啟動策略

我們可以在std::async傳遞任何回撥,如:

·函式指標

·函式物件

·lambda表示式

std::async的需求

假設我們必須從資料庫和檔案系統裡裡獲取一些資料(字串),然後需要合併字串並列印。

在單執行緒中,我們這樣做:

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
 
using namespace std::chrono;
 
std::string fetchDataFromDB(std::string recvData) {
 //確保函式要5秒才能執行完成
 std::this_thread::sleep_for(seconds(5));
 
 //處理建立資料庫連線、獲取資料等事情
 return "DB_" + recvData;
}
 
std::string fetchDataFromFile(std::string recvData) {
 //確保函式要5秒才能執行完成
 std::this_thread::sleep_for(seconds(5));
 
 //處理獲取檔案資料
 return "File_" + recvData;
}
 
int main() {
 //獲取開始時間
 system_clock::time_point start = system_clock::now();
 
 //從資料庫獲取資料
 std::string dbData = fetchDataFromDB("Data");
 
 //從檔案獲取資料
 std::string fileData = fetchDataFromFile("Data");
 
 //獲取結束時間
 auto end = system_clock::now();
 
 auto diff = duration_cast<std::chrono::seconds>(end - start).count();
 std::cout << "Total Time taken= " << diff << "Seconds" << std::endl;
 
 //組裝資料
 std::string data = dbData + " :: " + fileData;
 
 //輸出組裝的資料
 std::cout << "Data = " << data << std::endl;
 
 return 0;
}

輸出:

Total Time Taken = 10 Seconds
Data = DB_Data :: File_Data

由於函式 fetchDataFromDB() 和 fetchDataFromFile()各自在單獨的執行緒中執行5秒,所以,總共耗時10秒。

既然從資料庫和檔案系統中獲取資料是獨立的並且都要耗時,那我們可以並行地執行他們。

一種方式是建立一個新的執行緒傳遞一個promise作為執行緒函式的引數,並在呼叫執行緒中從關聯的std::future物件獲取資料

另一種方式就是使用std::async

使用函式指標呼叫std::async作為回撥

修改上面的程式碼,並使用std::async非同步呼叫fetchDataFromDB()

std::future<std::string>resultFromDB = std::async(std::launch::async,fetchDataFromDB,"Data");
 
std::string dbData = resultDromDB.get()

std::async()做如下的事情

·自動建立一個執行緒(或從內部執行緒池中挑選)和一個promise物件。

·然後將std::promise物件傳遞給執行緒函式,並返回相關的std::future物件

·當我們傳遞引數的函式退出時,它的值將被設定在這個promise物件中,所以最終的返回值將在std::future物件中可用

現在改變上面的例子,使用std::async非同步地從資料庫中獲取資料

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <future>
 
using namespace std::chrono;
 
std::string fetchDataFromDB(std::string recvData) {
 //確保函式要5秒才能執行完成
 std::this_thread::sleep_for(seconds(5));
 
 //處理建立資料庫連線、獲取資料等事情
 return "DB_" + recvData;
}
 
std::string fetchDataFromFile(std::string recvData) {
 //確保函式要5秒才能執行完成
 std::this_thread::sleep_for(seconds(5));
 
 //處理獲取檔案資料
 return "File_" + recvData;
}
 
int main() {
 //獲取開始時間
 system_clock::time_point start = system_clock::now();
 
 std::future<std::string> resultFromDB = std::async(std::launch::async,"Data");
 
 //從檔案獲取資料
 std::string fileData = fetchDataFromFile("Data");
 
 //從DB獲取資料
 //資料在future<std::string>物件中可獲取之前,將一直阻塞
 std::string dbData = resultFromDB.get();
 
 //獲取結束時間
 auto end = system_clock::now();
 
 auto diff = duration_cast<std::chrono::seconds>(end - start).count();
 std::cout << "Total Time taken= " << diff << "Seconds" << std::endl;
 
 //組裝資料
 std::string data = dbData + " :: " + fileData;
 
 //輸出組裝的資料
 std::cout << "Data = " << data << std::endl;
 
 return 0;
}

輸出:

Total Time taken= 5Seconds
Data = DB_Data :: File_Data

只使用了5秒

用Function物件作為回撥呼叫std::async

/*
* Function Object
*/
struct DataFetcher {
 std::string operator ()(std::string recvdData) {
  //確保函式要5秒才能執行完成
  std::this_thread::sleep_for(seconds(5));
  //處理獲取檔案資料
  return "File_" + recvdData;
 
 }
};
 
//用函式物件呼叫std::async
std::future<std::string> fileResult = std::async(DataFetcher(),"Data"); 

用lambda函式作為回撥呼叫std::async

std::future<std::string> resultFromDB = std::async([](std::string recvdData) {
 
 std::this_thread::sleep_for(seconds(5));
 //處理建立資料庫連線、獲取資料等事情
 return "DB_" + recvdData;
 
},"Data"); 

總結

到此這篇關於c++11多執行緒程式設計之std::async的文章就介紹到這了,更多相關c++11多執行緒程式設計std::async內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!