c++ - 何时在 async 或 packaged_task 上使用 promise?

标签 c++ asynchronous promise future packaged-task

我什么时候应该使用 std::promise 而不是 std::asyncstd::packaged_task? 你能给我具体的例子来说明什么时候使用它们吗?

最佳答案

std::async

std::async 是获得 std::future 的简洁而简单的方法,但是:

  • 它并不总是启动一个新线程;枚举值 std::launch::async可以作为第一个参数传递给 std::async为了确保创建一个新线程来执行func指定的任务,从而确保 func异步执行。

      auto f = std::async( std::launch::async, func );
    
  • destructor of std::future can block until the new thread completes .

      auto sleep = [](int s) { std::this_thread::sleep_for(std::chrono::seconds(s)); };
    
      {
          auto f = std::async( std::launch::async, sleep, 5 );
      }
    

通常我们期望只有 .get().wait() block ,但对于 std::futurestd::async 返回,析构函数也可能阻塞,所以注意不要因为忘记它而阻塞你的主线程。

  • 如果 std::future存储在一个临时对象中,std::async call 将在对象销毁时阻塞,因此如果您删除 auto f =,接下来的阻塞将花费 10 秒初始化。它只会阻塞 5 秒 否则,因为两个 sleep 将是并发的,由于阻塞结束时两个对象的破坏而等待两者完成:

      auto sleep = [](int s) { std::this_thread::sleep_for(std::chrono::seconds(s)); };
    
      {
          auto f1 = std::async( std::launch::async, sleep, 5 );
          auto f2 = std::async( std::launch::async, sleep, 5 );
      }
    

std::packaged_task

std::packaged_task 本身与线程无关:它只是一个仿函数和一个相关的std::future .考虑以下几点:

auto task = [](int i) {
   std::this_thread::sleep_for(std::chrono::seconds(5));
   return i+100;
};

std::packaged_task< int(int) > package{ task };
std::future<int> f = package.get_future();
package(1);
std::cout << f.get() << "\n";

这里我们只是运行 package(1) 的任务,返回后,f已准备就绪,因此不会阻塞 .get() .

std::packaged_task有一个特点这使得它对线程非常有用。您可以初始化 std::thread 而不仅仅是一个函数与 std::packaged_task这提供了一种非常好的方式来获得“std::future”。考虑以下几点:

std::packaged_task< int(int) > package{ task };
std::future<int> f = package.get_future();
std::thread t { std::move(package), 5 };

std::cout << f.get() << "\n";       //block here until t finishes

t.join();

因为std::packaged_task不可复制,您必须使用 std::move 将其移至新线程.

std::promise

std::promise 是一种强大的机制。例如,您可以将值传递给新线程,而无需任何额外的同步。

auto task = [](std::future<int> i) {
    std::cout << i.get() << std::flush;
};

std::promise<int> p;
std::thread t{ task, p.get_future() };

std::this_thread::sleep_for(std::chrono::seconds(5));
p.set_value(5);

t.join();

新线程将在 .get() 上等待我们


所以,一般来说,回答你的问题:

  • 使用std::async仅适用于简单的事情,例如使一些调用非阻塞,但请记住上面关于阻塞的评论。

  • 使用std::packaged_task轻松访问 std::future ,并将其作为单独的线程运行

      std::thread{ std::move(package), param }.detach();
    

    std::thread t { std::move(package), param };
  • 使用 std::promise当您需要对 future 进行更多控制时。

另见 std::shared_future 以及在线程之间传递异常 std::promise::set_exception

关于c++ - 何时在 async 或 packaged_task 上使用 promise?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17729924/

相关文章:

c++ - 有关唯一指针的问题

c++ - 任意浮点值与无穷大相比如何?

multithreading - 原子映射内的 Clojure Promise

javascript - 如何使用 Jasmine 在 AngularJS 中测试 .catch Promise 返回?

c++ - std::list 和垃圾收集算法

C++ If语句错误: expected ';' before '{' token

linux - 如何在linux中做异步IO?

iphone - dispatch_semaphore_wait 停止 iPhone APP 中的所有线程

Javascript 异步函数控制台记录返回的数据

javascript - 为 promise 编写循环的正确方法。