翻译来自:C++11 Multithreading – Part 9: std::async Tutorial & Example
在本文中,我们将讨论如何在C ++ 11中使用std :: async异步执行任务。
std :: async在c ++ 11中引入。
什么是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 ,该值存储由std :: async()执行的函数对象返回的值。函数期望的参数可以在函数指针参数之后作为参数传递给std :: async()。
std :: async中的第一个参数是启动策略,它控制std :: async的异步行为。我们可以使用3种不同的启动策略创建std :: async,即
-
std :: launch :: async
- 它保证了异步行为,即传递的函数将在单独的线程中执行。
-
std :: launch :: deferred
- 非异步行为,即当其他线程将来调用get()以访问共享状态时,将调用Function。
-
std :: launch :: async | std :: launch :: deferred
- 它是默认行为。使用此启动策略,它可以异步运行或不异步运行,具体取决于系统上的负载。但是我们无法控制它。
如果我们不指定启动策略。它的行为类似于std :: launch :: async | std :: launch :: deferred。
在本文中,我们将使用std :: launch :: async启动策略。
我们可以在std :: async中传递任何回调,即
- 功能指针
- 功能对象
- Lambda函数
让我们通过一个例子来了解std :: async的需求,
需要std :: async()
假设我们必须从数据库中获取一些数据(字符串),并从文件系统中的文件中获取一些数据。然后,我需要合并两个字符串并进行打印。
在一个线程中,我们将这样做,
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
using namespace std::chrono;
std::string fetchDataFromDB(std::string recvdData)
{
// Make sure that function takes 5 seconds to complete
std::this_thread::sleep_for(seconds(5));
//Do stuff like creating DB Connection and fetching Data
return "DB_" + recvdData;
}
std::string fetchDataFromFile(std::string recvdData)
{
// Make sure that function takes 5 seconds to complete
std::this_thread::sleep_for(seconds(5));
//Do stuff like fetching Data File
return "File_" + recvdData;
}
int main()
{
// Get Start Time
system_clock::time_point start = system_clock::now();
//Fetch Data from DB
std::string dbData = fetchDataFromDB("Data");
//Fetch Data from File
std::string fileData = fetchDataFromFile("Data");
// Get End Time
auto end = system_clock::now();
auto diff = duration_cast < std::chrono::seconds > (end - start).count();
std::cout << "Total Time Taken = " << diff << " Seconds" << std::endl;
//Combine The Data
std::string data = dbData + " :: " + fileData;
//Printing the combined Data
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");
// Do Some Stuff
//Fetch Data from DB
// Will block till data is available in future<std::string> object.
std::string dbData = resultFromDB.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 recvdData)
{
// Make sure that function takes 5 seconds to complete
std::this_thread::sleep_for(seconds(5));
//Do stuff like creating DB Connection and fetching Data
return "DB_" + recvdData;
}
std::string fetchDataFromFile(std::string recvdData)
{
// Make sure that function takes 5 seconds to complete
std::this_thread::sleep_for(seconds(5));
//Do stuff like fetching Data File
return "File_" + recvdData;
}
int main()
{
// Get Start Time
system_clock::time_point start = system_clock::now();
std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
//Fetch Data from File
std::string fileData = fetchDataFromFile("Data");
//Fetch Data from DB
// Will block till data is available in future<std::string> object.
std::string dbData = resultFromDB.get();
// Get End Time
auto end = system_clock::now();
auto diff = duration_cast < std::chrono::seconds > (end - start).count();
std::cout << "Total Time Taken = " << diff << " Seconds" << std::endl;
//Combine The Data
std::string data = dbData + " :: " + fileData;
//Printing the combined Data
std::cout << "Data = " << data << std::endl;
return 0;
}
现在只需要5秒钟。
输出
Total Time Taken = 5 Seconds
Data = DB_Data :: File_Data
使用函数对象作为回调调用std :: async
/*
* Function Object
*/
struct DataFetcher
{
std::string operator()(std::string recvdData)
{
// Make sure that function takes 5 seconds to complete
std::this_thread::sleep_for (seconds(5));
//Do stuff like fetching Data File
return "File_" + recvdData;
}
};
//Calling std::async with function object
std::future<std::string> fileResult = std::async(DataFetcher(), "Data");
使用Lambda函数作为回调调用std :: async
//Calling std::async with lambda function
std::future<std::string> resultFromDB = std::async([](std::string recvdData){
std::this_thread::sleep_for (seconds(5));
//Do stuff like creating DB Connection and fetching Data
return "DB_" + recvdData;
}, "Data");