PPL when_all 有不同类型的任务?
PPL when_all with tasks of different types?
我想在不同类型的任务上使用 PPL "when_all"。并向该任务添加 "then" 调用。
但是 when_all returns 任务采用向量,因此所有元素必须是同一类型。那么我该怎么做呢?
这是我想出的,但感觉有点乱:
//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 块所以我不想使用它)
任务组会起作用。
否则:
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
任务,但可以将任何一组任务捆绑到一个元组任务中。
让 void
工作需要更多的工作。一种方法是编写 get_safe
,returns T
对应 task<T>
,void_placeholder
对应 task<void>
,然后在返回前过滤生成的元组。或者编写一个 partition_args
将 args 拆分为 task<void>
和 task<T>
,并对它们两个采取不同的操作。两者都有些头疼。我们也可以做一个元组附加模式(我们一次处理一个任务,并且可以将 T
附加到 tuple
或不对 void
做任何事情).
它使用了两个 C++14 库特性(index_sequence 和 index_sequence_for),但两者都很容易用 C++11 编写(每个 2-4 行),并且实现是很容易找到。
我忘了任务是否可复制,我假设它不在上面的代码中。如果它是可复制的,则上述代码的较短版本将起作用。对任何拼写错误表示歉意。
我想在不同类型的任务上使用 PPL "when_all"。并向该任务添加 "then" 调用。
但是 when_all returns 任务采用向量,因此所有元素必须是同一类型。那么我该怎么做呢?
这是我想出的,但感觉有点乱:
//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 块所以我不想使用它)
任务组会起作用。
否则:
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
任务,但可以将任何一组任务捆绑到一个元组任务中。
让 void
工作需要更多的工作。一种方法是编写 get_safe
,returns T
对应 task<T>
,void_placeholder
对应 task<void>
,然后在返回前过滤生成的元组。或者编写一个 partition_args
将 args 拆分为 task<void>
和 task<T>
,并对它们两个采取不同的操作。两者都有些头疼。我们也可以做一个元组附加模式(我们一次处理一个任务,并且可以将 T
附加到 tuple
或不对 void
做任何事情).
它使用了两个 C++14 库特性(index_sequence 和 index_sequence_for),但两者都很容易用 C++11 编写(每个 2-4 行),并且实现是很容易找到。
我忘了任务是否可复制,我假设它不在上面的代码中。如果它是可复制的,则上述代码的较短版本将起作用。对任何拼写错误表示歉意。