【问题标题】:Different execution policies at runtime运行时不同的执行策略
【发布时间】:2018-10-24 17:45:53
【问题描述】:

在 C++17 中,algorithm 标头中的许多函数现在可以采用执行策略。例如,我可以定义和调用这样的函数:

template <class ExecutionPolicy>
void f1(const std::vector<std::string>& vec, const std::string& elem, ExecutionPolicy&& policy) {
    const auto it = std::find(
        std::forward<ExecutionPolicy>(policy),
        vec.cbegin(), vec.cend(), elem
    );
}

std::vector<std::string> vec;
f1(vec, "test", std::execution::seq);

但是我还没有找到在运行时使用不同策略的好方法。例如,当我想根据某些输入文件使用不同的策略时。

我玩弄了各种变体,但最终问题始终是 std::execution::seqstd::execution::parstd::execution::par_unseq 的不同类型。

一个可行但繁琐的解决方案如下所示:

void f2(const std::vector<std::string>& vec, const std::string& elem, const int policy) {
    const auto it = [&]() {
        if (policy == 0) {
            return std::find(
                std::execution::seq,
                vec.cbegin(), vec.cend(), elem
            );
        }
        else if (policy == 1) {
            return std::find(
                std::execution::par,
                vec.cbegin(), vec.cend(), elem
            );
        }
        else{
            return std::find(
                std::execution::par_unseq,
                vec.cbegin(), vec.cend(), elem
            );
        }
    };
}

f2(vec, "test", 0);

我忽略了任何更优雅的解决方案吗?

编辑:也许我应该更准确。假设目标是将策略保存在一个变量中,该变量可以具有三个策略中的任何一个。该变量应该是函数的参数。

【问题讨论】:

  • 这完全取决于选择的来源。例如,如果不将policy 变量限制为int,您可以直接将ExecutionPolicy 传递给f2。但大概你有一些限制,我们不知道那是什么。
  • 但问题是,据我了解,这三个策略没有共同的基类。这正是让这件事变得如此棘手的原因
  • 哦,对了。嗯,嗯。最好的解决方案仍然取决于“选择”的来源。您可能可以使用 constexpr 向量或其他东西将整数映射到类型。虽然这仍然不能完全帮助你。不确定;祝你好运!

标签: c++ parallel-processing


【解决方案1】:

这里的标准方法是将类型的选择与类型的使用分开:后者采用函数模板的形式,由以前的非模板函数(或模板参数较少的函数模板)。

为避免在这两层之间重复正常参数,请使用通用 lambda 作为模板。为避免重复选择逻辑,请使用适当的策略创建一个调用任何 lambda 的函数模板:

enum Policy {seq,par,par_unseq};

template<class F>
auto maybe_parallel(F f,Policy p) {
  switch(p) {
  case seq: return f(std::execution::seq);
  case par: return f(std::execution::par);
  default: return f(std::execution::par_unseq);
  }
}

auto f2(const std::vector<std::string>& vec,
        const std::string& elem,Policy p) {
  return maybe_parallel
    ([&](auto &pol) {return std::find(pol,vec.begin(),vec.end(),elem);},p);
}

【讨论】:

  • 嘿哇,这似乎很聪明。我稍后会试试。非常感谢!
【解决方案2】:

另一种方法是为此目的使用std::variantstd::visit

using parallel_policy = std::variant
                        <
                         std::execution::sequenced_policy,
                         std::execution::parallel_policy,
                         std::execution::parallel_unsequenced_policy,
                         std::execution::unsequenced_policy
                        >;

void f2(const std::vector<std::string>& vec,
        const std::string&              elem,
        const parallel_policy           policy
       )
{
    std::visit
    (
        [&](auto policy_real)
        {
            f1(vec, elem, policy_real);
        },
        policy
    );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-04
    • 1970-01-01
    • 2021-12-11
    • 1970-01-01
    相关资源
    最近更新 更多