建议使用 Visual Studio 2017

演练:实现 Future

 

若要了解有关 Visual Studio 2017 RC 的最新文档,请参阅 Visual Studio 2017 RC 文档

本主题演示如何在您的应用程序中实现 future。 本主题演示如何结合使用现有功能在并发运行时转换的内容的详细信息。

System_CAPS_ICON_important.jpg 重要事项

为了便于演示,本主题阐释将来的概念。 我们建议你使用 std:: futureconcurrency:: task 当您需要计算该值以备将来使用的异步任务。

一个 任务 是可以分解为更多、 更细粒度的计算的计算。 一个 将来 是计算更高版本使用的值是一个异步任务。

若要实现 future,本主题定义 async_future 类。 async_future 类使用并发运行时的以下组件︰ concurrency:: task_group 类和 concurrency:: single_assignment 类。 async_future 类使用 task_group 类来异步计算值与 single_assignment 类来存储计算的结果。 构造函数 async_future 类采用计算结果,一个工作函数和 get 方法将检索结果。

实现 async_future 类

  1. 声明一个名为模板类 async_future ,已生成的计算的类型参数化。 添加 publicprivate 与此类的部分。

template <typename T>
class async_future
{
public:
private:
};

  1. private 部分 async_future 类中,声明 task_groupsingle_assignment 数据成员。

   // Executes the asynchronous work function.
   task_group _tasks;

   // Stores the result of the asynchronous work function.
   single_assignment<T> _value;

  1. public 部分 async_future 类中,实现构造函数。 构造函数是计算结果的工作函数参数化的模板。 以异步方式执行的构造函数中的工作函数 task_group 数据成员,并使用 concurrency:: send 函数以将结果写入 single_assignment 数据成员。

   template <class Functor>
   explicit async_future(Functor&& fn)
   {
      // Execute the work function in a task group and send the result
      // to the single_assignment object.
      _tasks.run([fn, this]() {
         send(_value, fn());
       });
   }

  1. public 部分 async_future 类,请实现析构函数。 析构函数等待任务完成。

   ~async_future()
   {
      // Wait for the task to finish.
      _tasks.wait();
   }

  1. public 部分 async_future 类,请实现 get 方法。 此方法使用 concurrency:: receive 函数以检索工作函数的结果。

   // Retrieves the result of the work function.
   // This method blocks if the async_future object is still 
   // computing the value.
   T get()
   { 
      return receive(_value); 
   }

描述

下面的示例演示了完整 async_future 类,其用法的示例。 wmain 函数创建 std::向量 对象,其中包含 10000 随机整数值。 然后,它使用 async_future 对象查找中包含的最小和最大值 vector 对象。

代码

// futures.cpp
// compile with: /EHsc
#include <ppl.h>
#include <agents.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <random>

using namespace concurrency;
using namespace std;

template <typename T>
class async_future
{
public:
   template <class Functor>
   explicit async_future(Functor&& fn)
   {
      // Execute the work function in a task group and send the result
      // to the single_assignment object.
      _tasks.run([fn, this]() {
         send(_value, fn());
       });
   }

   ~async_future()
   {
      // Wait for the task to finish.
      _tasks.wait();
   }

   // Retrieves the result of the work function.
   // This method blocks if the async_future object is still 
   // computing the value.
   T get()
   { 
      return receive(_value); 
   }

private:
   // Executes the asynchronous work function.
   task_group _tasks;

   // Stores the result of the asynchronous work function.
   single_assignment<T> _value;
};

int wmain()
{
   // Create a vector of 10000 integers, where each element 
   // is between 0 and 9999.
   mt19937 gen(2);
   vector<int> values(10000);   
   generate(begin(values), end(values), [&gen]{ return gen()%10000; });

   // Create a async_future object that finds the smallest value in the
   // vector.
   async_future<int> min_value([&]() -> int { 
      int smallest = INT_MAX;
      for_each(begin(values), end(values), [&](int value) {
         if (value < smallest)
         {
            smallest = value;
         }
      });
      return smallest;
   });
   
   // Create a async_future object that finds the largest value in the
   // vector.
   async_future<int> max_value([&]() -> int { 
      int largest = INT_MIN;
      for_each(begin(values), end(values), [&](int value) {
         if (value > largest)
         {
            largest = value;
         } 
      });
      return largest;
   });

   // Calculate the average value of the vector while the async_future objects
   // work in the background.
   int sum = accumulate(begin(values), end(values), 0);
   int average = sum / values.size();

   // Print the smallest, largest, and average values.
   wcout << L"smallest: " << min_value.get() << endl
         << L"largest:  " << max_value.get() << endl
         << L"average:  " << average << endl;
}

注释

该示例产生下面的输出:

smallest: 0  
largest:  9999  
average:  4981  

该示例使用 async_future::get 方法来检索计算结果。 async_future::get 方法等待计算完成计算是否仍处于活动状态。

若要扩展 async_future 类来处理工作函数引发的异常,请修改 async_future::get 方法来调用 concurrency::task_group::wait 方法。 task_group::wait 方法将引发生成的工作函数的任何异常。

下面的示例演示的修改的版本 async_future 类。 wmain 函数使用 try-catch 块来输出结果的 async_future 对象或要打印的值生成的工作函数的异常。

// futures-with-eh.cpp
// compile with: /EHsc
#include <ppl.h>
#include <agents.h>
#include <vector>
#include <algorithm>
#include <iostream>

using namespace concurrency;
using namespace std;

template <typename T>
class async_future
{
public:
   template <class Functor>
   explicit async_future(Functor&& fn)
   {
      // Execute the work function in a task group and send the result
      // to the single_assignment object.
      _tasks.run([fn, this]() {
         send(_value, fn());
       });
   }

   ~async_future()
   {
      // Wait for the task to finish.
      _tasks.wait();
   }

   // Retrieves the result of the work function.
   // This method blocks if the async_future object is still
   // computing the value.
   T get()
   { 
      // Wait for the task to finish.
      // The wait method throws any exceptions that were generated
      // by the work function.
      _tasks.wait();

      // Return the result of the computation.
      return receive(_value);
   }

private:
   // Executes the asynchronous work function.
   task_group _tasks;

   // Stores the result of the asynchronous work function.
   single_assignment<T> _value;
};

int wmain()
{
   // For illustration, create a async_future with a work 
   // function that throws an exception.
   async_future<int> f([]() -> int { 
      throw exception("error");
   });

   // Try to read from the async_future object. 
   try
   {
      int value = f.get();
      wcout << L"f contains value: " << value << endl;
   }
   catch (const exception& e)
   {
      wcout << L"caught exception: " << e.what() << endl;
   }
}

该示例产生下面的输出:

caught exception: error  

有关并发运行时中的异常处理模型的详细信息,请参阅 异常处理

复制代码示例并将其粘贴到 Visual Studio 项目中,或粘贴到名为 futures.cpp ,然后在 Visual Studio 命令提示窗口中运行以下命令。

cl.exe /EHsc futures.cpp

并发运行时演练
异常处理
task_group 类
single_assignment 类

显示: