다음을 통해 공유


연습: 미래 구현

이 항목에서는 애플리케이션에서 미래를 구현하는 방법을 보여 줍니다. 이 항목에서는 동시성 런타임의 기존 기능을 더 많은 작업을 수행하는 기능으로 결합하는 방법을 보여 줍니다.

Important

이 항목에서는 이해를 돕기 위해 미래의 개념에 대해 설명합니다. 나중에 사용할 값을 계산하는 비동기 작업이 필요한 경우 std::future 또는 concurrency::task 를 사용하는 것이 좋습니다.

작업은 더 세분화된 추가 계산으로 분해할 수 있는 계산입니다. 미래는 나중에 사용할 값을 계산하는 비동기 작업입니다.

미래를 구현하기 위해 이 항목에서는 클래스를 async_future 정의합니다. 클래스는 async_future 동시성 런타임의 이러한 구성 요소인 동시성::task_group 클래스 및 동시성::single_assignment 클래스를 사용합니다. 클래스는 async_future 클래스를 task_group 사용하여 값을 비동기적으로 계산하고 클래스를 single_assignment 사용하여 계산 결과를 저장합니다. 클래스의 async_future 생성자는 결과를 계산하는 작업 함수를 사용하고 메서드는 get 결과를 검색합니다.

async_future 클래스를 구현하려면

  1. 결과 계산의 형식에 매개 변수가 있는 명명 async_future 된 템플릿 클래스를 선언합니다. 이 클래스에 섹션을 private 추가하고 섹션을 추가 public 합니다.
template <typename T>
class async_future
{
public:
private:
};
  1. private 클래스의 async_future 섹션에서 a task_group 및 데이터 멤버를 선언합니다single_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 작업 함수를 비동기적으로 실행하고 동시성::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 . 이 메서드는 동시성::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 10,000개의 임의 정수 값을 포함하는 std::vector 개체를 만듭니다. 그런 다음 개체를 사용하여 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 throw된 예외를 처리하도록 클래스를 확장하려면 동시성::task_group::wait 메서드를 호출하도록 메서드를 수정 async_future::get 합니다. 이 메서드는 task_group::wait 작업 함수에 의해 생성된 모든 예외를 throw합니다.

다음 예제에서는 클래스의 async_future 수정된 버전을 보여줍니다. 이 함수는 wmain 블록을 사용하여catch try-개체의 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 클래스