std::async
foi introduzido no C++11. Ele é um template de função que aceita funções de callback como argumento e potencialmente os executa de forma assíncrona.
Ou seja, utilizando-o você pode melhorar a velocidade de uma aplicação, pois o tempo de retorno é usado de forma paralela.
Podemos criar std::async
com 3 políticas de inicialização diferentes:
std::launch::async
- Ele garante o comportamento assíncrono, ou seja, a função passada será executada em uma thread separada.std::launch::deferred
- Comportamento não assíncrono, a função será chamada quando outro thread chamar get()
no futuro para acessar o estado compartilhado.std::launch::async | std::launch::deferred
- É o comportamento padrão. Com esta política de inicialização, ele pode ser executado de forma assíncrona ou não.Se não especificarmos uma política de inicialização, std::launch::async | std::launch::deferred
será utilizado.
No exemplo desse artigo vamos utilizar std::launch::async
.
Podemos passar qualquer tipo de função de callback em std::async
:
Suponhamos que estamos desenvolvendo uma aplicação que precisa consumir 2 APIs diferentes e os dados retornados dessas APIs precisamos concatenar com dados que possuímos para gerar um novo nome.
Sem usar std::async
faríamos mais ou menos assim:
Vamos ustilizar std::chrono para criar um
sleep
para dar impressão que seria o tempo de demora do retorno dos dados.
std::async
vim exemplo-sem-async.cpp
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
// Obter os dados da 1º API, tem um tempo de 2 segundos
std::string get_first_data_api(std::string ret_data){
// sleep de 2 segundos
std::this_thread::sleep_for( std::chrono::seconds(2));
return "FIRST_" + ret_data;
}
// Obter os dados da 2º API, tem também um tempo de 2 segundos
std::string get_second_data_api(std::string ret_data){
// sleep de 2 segundos
std::this_thread::sleep_for( std::chrono::seconds(2));
return "SECOND_" + ret_data;
}
int main(){
// Obtém o início do tempo para a contagem
std::chrono::system_clock::time_point start =
std::chrono::system_clock::now();
// Solicita os dados da primeira API
std::string first_api = get_first_data_api("NUMERO_UM");
// Solicita os dados da segunda API
std::string second_api = get_second_data_api("NUMERO_DOIS");
// Obtém o final do tempo
auto end = std::chrono::system_clock::now();
// Diferença do tempo para saber quanto tempo foi gasto
auto diff =
std::chrono::duration_cast<std::chrono::seconds>(end - start).count();
// Imprime o temp gasto
std::cout << "Tempo gasto para a requisição: " <<
diff << " Segundos" << '\n';
// Imprime a saída
std::cout <<
"Primeira API: "<< first_api <<
"\nSegunda API: " << second_api << '\n';
return 0;
}
A saída desse exemplo será 4 segundos, pois será somado o tempo da 1º API(2 segundos) mais o tempo da 2º API(2 segundos).
Tempo gasto para a requisição: 4 Segundos
Primeira API: FIRST_NUMERO_UM
Segunda API: SECOND_NUMERO_DOIS
Ou seja, um foi executado após o outro.
Agora vamos utilizar o mesmo código, mas vamos incluir somente TRÊS linhas para usar o std::async
:
#include <future>
// Solicita os dados da primeira API
, vamos alterar a linha para essa linha:std::future<std::string> result_api_one = std::async(std::launch::async, get_first_data_api, "NUMERO_UM");
std::string first_api = result_api_one.get();
Perceba que estamos agora utilizando std::future
para obter os dados via a função get()
.
std::async
vim exemplo-com-async.cpp
O código final com uso de std::async
ficaria assim:
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <future>
std::string get_first_data_api(std::string ret_data){
// sleep de 2 segundos
std::this_thread::sleep_for( std::chrono::seconds(2));
return "FIRST_" + ret_data;
}
std::string get_second_data_api(std::string ret_data){
// sleep de 2 segundos
std::this_thread::sleep_for( std::chrono::seconds(2));
return "SECOND_" + ret_data;
}
int main(){
// Obtém o início do tempo para a contagem
std::chrono::system_clock::time_point start =
std::chrono::system_clock::now();
// Solicita os dados da primeira API
std::future<std::string> result_api_one = std::async(std::launch::async, get_first_data_api, "NUMERO_UM");
// Solicita os dados da segunda API
std::string second_api = get_second_data_api("NUMERO_DOIS");
// Bloqueará até que os dados estejam disponíveis no objeto future<std::string>.
std::string first_api = result_api_one.get();
// Obtém o final do tempo
auto end = std::chrono::system_clock::now();
auto diff =
std::chrono::duration_cast<std::chrono::seconds>(end - start).count();
std::cout << "Tempo gasto para a requisição: " <<
diff << " Segundos" << '\n';
// Imprime a saída
std::cout <<
"Primeira API: "<< first_api <<
"\nSegunda API: " << second_api << '\n';
return 0;
}
Para compilar precisamos utilizar a flag: -pthread
, exemplo:
g++ -pthread exemplo-com-async.cpp
Agora note que a saída foram gastos somente 2 segundos, ou seja, a primeira API foi executada de forma paralela à segunda API, a saída será:
Tempo gasto para a requisição: 2 Segundos
Primeira API: FIRST_NUMERO_UM
Segunda API: SECOND_NUMERO_DOIS
Agora ficou mais fácil de entender, né?
Por hoje é só, são pequenas doses diárias que farão sempre nos manter antenado com o C++ !
Então se inscreva nos nossos Cursos de C++ Moderno . Você aprender criar:
Acesse o endereço: