分享方式:


如何:在已完成的工作之中選取

此範例示範如何使用 concurrency::choice concurrency::join 類別來選取第一個工作來完成搜尋演算法。

範例

下列範例會平行執行兩個搜尋演算法,並選取要完成的第一個演算法。 此範例會 employee 定義類型,此類型會保存員工的數值識別碼和薪資。 函 find_employee 式會尋找具有所提供識別碼或所提供工資的第一位員工。 函 find_employee 式也會處理沒有員工提供識別碼或薪資的情況。 函 wmain 式會建立 物件的陣列 employee ,並搜尋數個識別碼和薪資值。

此範例會使用 choice 物件來選取下列案例:

  1. 具有所提供識別碼的員工存在。

  2. 有提供工資的員工存在。

  3. 沒有提供識別碼或薪資的員工存在。

在前兩個案例中,此範例會使用 並行::single_assignment 物件來保存識別碼,而另一個 single_assignment 物件則保留薪資。 此範例會針對第三個 join 案例使用 物件。 物件 join 是由另外兩 single_assignment 個物件所組成,一個是沒有提供識別碼的員工存在的情況,另一個則用於沒有提供工資的員工存在的情況。 物件 join 會在每個成員收到訊息時傳送訊息。 在此範例中 join ,物件會在沒有提供識別碼或薪資的員工存在時傳送訊息。

此範例會使用並行::structured_task_group 物件平行執行這兩種 搜尋演算法。 每個搜尋工作都會寫入其中一個 物件, single_assignment 以指出指定的員工是否存在。 此範例會使用 並行::receive 函式來取得包含訊息和區塊的第一個 switch 緩衝區索引,以列印結果。

// find-employee.cpp
// compile with: /EHsc
#include <agents.h>
#include <ppl.h>
#include <array>
#include <iostream>
#include <random>

using namespace concurrency;
using namespace std;

// Contains information about an employee.
struct employee
{
   int id;
   float salary;
};

// Finds the first employee that has the provided id or salary.
template <typename T>
void find_employee(const T& employees, int id, float salary)
{
   // Holds the salary for the employee with the provided id.
   single_assignment<float> find_id_result;

   // Holds the id for the employee with the provided salary.
   single_assignment<int> find_salary_result;


   // Holds a message if no employee with the provided id exists.
   single_assignment<bool> id_not_found;

   // Holds a message if no employee with the provided salary exists.
   single_assignment<bool> salary_not_found;

   // Create a join object for the "not found" buffers.
   // This join object sends a message when both its members holds a message 
   // (in other words, no employee with the provided id or salary exists).
   auto not_found = make_join(&id_not_found, &salary_not_found);


   // Create a choice object to select among the following cases:
   // 1. An employee with the provided id exists.
   // 2. An employee with the provided salary exists.
   // 3. No employee with the provided id or salary exists.
   auto selector = make_choice(&find_id_result, &find_salary_result, &not_found);
   

   // Create a task that searches for the employee with the provided id.
   auto search_id_task = make_task([&]{
      auto result = find_if(begin(employees), end(employees), 
         [&](const employee& e) { return e.id == id; });
      if (result != end(employees))
      {
         // The id was found, send the salary to the result buffer.
         send(find_id_result, result->salary);
      }
      else
      {
         // The id was not found.
         send(id_not_found, true);
      }
   });

   // Create a task that searches for the employee with the provided salary.
   auto search_salary_task = make_task([&]{
      auto result = find_if(begin(employees), end(employees), 
         [&](const employee& e) { return e.salary == salary; });
      if (result != end(employees))
      {
         // The salary was found, send the id to the result buffer.
         send(find_salary_result, result->id);
      }
      else
      {
         // The salary was not found.
         send(salary_not_found, true);
      }
   });

   // Use a structured_task_group object to run both tasks.
   structured_task_group tasks;
   tasks.run(search_id_task);
   tasks.run(search_salary_task);

   wcout.setf(ios::fixed, ios::fixed);
   wcout.precision(2);

   // Receive the first object that holds a message and print a message.
   int index = receive(selector);
   switch (index)
   {
   case 0:
      wcout << L"Employee with id " << id << L" has salary " 
            << receive(find_id_result);
      break;
   case 1:
      wcout << L"Employee with salary " << salary << L" has id " 
            << receive(find_salary_result);
      break;
   case 2:
      wcout << L"No employee has id " << id << L" or salary " << salary;
      break;
   default:
      __assume(0);
   }
   wcout << L'.' << endl;
   
   // Cancel any active tasks and wait for the task group to finish.
   tasks.cancel();
   tasks.wait();
}

int wmain()
{
   // Create an array of employees and assign each one a 
   // random id and salary.

   array<employee, 10000> employees;
   
   mt19937 gen(15);
   const float base_salary = 25000.0f;
   for (int i = 0; i < employees.size(); ++i)
   {
      employees[i].id = gen()%100000;

      float bonus = static_cast<float>(gen()%5000);
      employees[i].salary = base_salary + bonus;
   }

   // Search for several id and salary values.

   find_employee(employees, 14758, 30210.00);
   find_employee(employees, 340, 29150.00);
   find_employee(employees, 61935, 29255.90);
   find_employee(employees, 899, 31223.00);
}

此範例會產生下列輸出。

Employee with id 14758 has salary 27780.00.
Employee with salary 29150.00 has id 84345.
Employee with id 61935 has salary 29905.00.
No employee has id 899 or salary 31223.00.

此範例會使用 平行存取::make_choice 協助程式函式來建立 choice 物件,並使用 並行::make_join 協助程式函式來建立 join 物件。

編譯程式碼

複製範例程式碼,並將其貼到 Visual Studio 專案中,或貼到名為 find-employee.cpp 的檔案中,然後在 Visual Studio 命令提示字元視窗中執行下列命令。

cl.exe /EHsc find-employee.cpp

另請參閱

非同步代理程式程式庫
非同步訊息區
訊息傳遞函式
choice 類別
join 類別