En realidad, el ejemplo que acaba de mostrar muestra las diferencias si utiliza una función bastante larga, como
//! sleeps for one second and returns 1
auto sleep = [](){
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
Tarea empaquetada
A packaged_taskno se iniciará solo, debe invocarlo:
std::packaged_task<int()> task(sleep);
auto f = task.get_future();
task(); // invoke the function
// You have to wait until task returns. Since task calls sleep
// you will have to wait at least 1 second.
std::cout << "You can see this after 1 second\n";
// However, f.get() will be available, since task has already finished.
std::cout << f.get() << std::endl;
std::async
Por otro lado, std::asyncwith launch::asyncintentará ejecutar la tarea en un hilo diferente:
auto f = std::async(std::launch::async, sleep);
std::cout << "You can see this immediately!\n";
// However, the value of the future will be available after sleep has finished
// so f.get() can block up to 1 second.
std::cout << f.get() << "This will be shown after a second!\n";
Retirarse
Pero antes de intentar usarlo asyncpara todo, tenga en cuenta que el futuro devuelto tiene un estado compartido especial, que exige que future::~futurebloquee:
std::async(do_work1); // ~future blocks
std::async(do_work2); // ~future blocks
/* output: (assuming that do_work* log their progress)
do_work1() started;
do_work1() stopped;
do_work2() started;
do_work2() stopped;
*/
Entonces, si desea una verdadera asíncrona, debe conservar la devolución future, o si no le importa el resultado si las circunstancias cambian:
{
auto pizza = std::async(get_pizza);
/* ... */
if(need_to_go)
return; // ~future will block
else
eat(pizza.get());
}
Para obtener más información sobre esto, ver el artículo de Herb Sutter asyncy~future , que describe el problema, y Scott Meyer std::futuresde std::asyncque no son especiales , que describe los puntos de vista. También tenga en cuenta que este comportamiento se especificó en C ++ 14 y versiones posteriores , pero también se implementó comúnmente en C ++ 11.
Diferencias adicionales
Al usarlo std::async, ya no puede ejecutar su tarea en un hilo específico, donde std::packaged_taskse puede mover a otros hilos.
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::thread myThread(std::move(task),2,3);
std::cout << f.get() << "\n";
Además, packaged_taskdebe invocarse antes de llamar f.get(), de lo contrario su programa se congelará ya que el futuro nunca estará listo:
std::packaged_task<int(int,int)> task(...);
auto f = task.get_future();
std::cout << f.get() << "\n"; // oops!
task(2,3);
TL; DR
Úselo std::asyncsi desea que se hagan algunas cosas y realmente no le importa cuándo se hacen, y std::packaged_tasksi desea concluir las cosas para moverlas a otros hilos o llamarlas más tarde. O, para citar a Christian :
Al final, a std::packaged_taskes solo una característica de nivel inferior para implementar std::async(por lo que puede hacer más que std::asyncsi se usa junto con otras cosas de nivel inferior, como std::thread). Simplemente dicho una std::packaged_taskes un std::functionvinculados a una std::futurey std::asyncenvolturas y llama a un std::packaged_task(posiblemente en un hilo diferente).
std::packaged_taskes solo una característica de nivel inferior para implementarstd::async(por lo que puede hacer más questd::asyncsi se usa junto con otras cosas de nivel inferior, comostd::thread). Simplemente dicho unastd::packaged_taskes unstd::functionvinculados a unastd::futureystd::asyncenvolturas y llama a unstd::packaged_task(posiblemente en un hilo diferente).Tarea empaquetada vs asíncrono
p> La tarea empaquetada contiene una tarea
[function or function object]y un par futuro / promesa. Cuando la tarea ejecuta una declaración de devolución, se produceset_value(..)lapackaged_taskpromesa de.a> Dadas las tareas de futuro, promesa y paquete, podemos crear tareas simples sin preocuparnos demasiado por los hilos [el hilo es solo algo que damos para ejecutar una tarea].
Sin embargo, debemos considerar cuántos hilos usar o si una tarea se ejecuta mejor en el hilo actual o en otro, etc. Tales decisiones pueden ser manejadas por un lanzador de hilos llamado
async(), que decide si crear un nuevo hilo o reciclar un viejo uno o simplemente ejecute la tarea en el hilo actual. Devuelve un futuro.fuente
fuente