【问题标题】:PPL when_all with tasks of different types?PPL when_all 具有不同类型的任务?
【发布时间】:2015-06-20 20:20:31
【问题描述】:

我想在不同类型的任务上使用 PPL“when_all”。并为该任务添加一个“then”调用。

但是 when_all 返回带有向量的任务,所以所有元素必须是相同的类型。那么我该怎么做呢?

这是我想出的,但感觉有点像 hack:

//3 different types:
int out1;
float out2;
char out3;

//Unfortunately I cant use tasks with return values as the types would be  different ...
auto t1 = concurrency::create_task([&out1](){out1 = 1; }); //some expensive operation
auto t2 = concurrency::create_task([&out2](){out2 = 2; }); //some expensive operation
auto t3 = concurrency::create_task([&out3](){out3 = 3; }); //some expensive operation

auto t4 = (t1 && t2 && t3); //when_all doesnt block

auto t5 = t4.then([&out1, &out2, &out3](){
    std::string ret = "out1: " + std::to_string(out1) + ", out2: " + std::to_string(out2) + ", out3: " + std::to_string(out3);
    return ret;
});
auto str = t5.get();

std::cout << str << std::endl;

谁有更好的主意?

(parallel_invoke 块,所以我不想使用它)

【问题讨论】:

    标签: c++ tbb ppl


    【解决方案1】:

    任务组将起作用。

    失败了:

    template<class...Ts>
    struct get_many{
      std::tuple<task<Ts>...> tasks;
      template<class T0, size_t...Is>
      std::tuple<T0,Ts...>
      operator()(
        std::task<T0> t0,
        std::index_sequence<Is...>
      ){
        return std::make_tuple(
          t0.get(),
          std::get<Is>(tasks).get()...
        );
      }
      template<class T0>
      std::tuple<T0,Ts...>
      operator()(task<T0> t0){
        return (*this)(
          std::move(t0),
          std::index_sequence_for<Ts...>{}
        );
      }
    };
    
    template<class T0, class...Ts>
    task<std::tuple<T0,Ts...>> when_every(
      task<T0> next, task<Ts>... later
    ){
      return next.then( get_many<Ts...>{
        std::make_tuple(std::move(later)...)
      } );
    }
    

    它不适用于void 任务,但会将任何一组任务捆绑到一个元组任务中。

    voids 工作需要更多的工作。一种方法是编写一个get_safe,为task&lt;T&gt; 返回T,为void_placeholdertask&lt;void&gt;,然后在返回之前过滤结果元组。或者写一个 partition_args 将 args 拆分为 task&lt;void&gt;task&lt;T&gt;,并对他们两个采取不同的行动。两人都有些头疼。我们还可以执行元组附加模式(我们一次处理一个任务,并且可以将T 附加到tuple 或对void 不执行任何操作)。

    它使用了两个 C++14 库特性(index_sequence 和 index_sequence_for),但两者都很容易用 C++11 编写(每个 2-4 行),并且很容易找到实现。

    我忘记了任务是否可复制,我认为它不在上面的代码中。如果它是可复制的,则上述代码的较短版本将起作用。对任何错别字表示歉意。

    【讨论】:

    • 谢谢。 tuple 而不是 vector 是一个很好的界面。我在这里可能错了,但我的印象是我应该避免调用 get(或等待)。因为它们阻止并扼杀了可扩展性。因此,在我看来,实现一个在幕后调用“get”的自定义“when_all”似乎是错误的。查看 concurrency::when_all 的实现,看起来只有在所有任务完成后才调用“get”,因此它不会阻塞。但我在这里超出了我的深度。最后,我不确定如何以非阻塞方式将任务延续链接和连接在一起。
    • @someone get 仅在 then 内调用,then 代码异步运行(我假设,因为它返回 task),希望在线程中第一个任务。
    • 酷,我的错。谢谢。
    猜你喜欢
    • 2017-10-15
    • 1970-01-01
    • 2019-08-20
    • 2011-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多