我需要一个函数来计算GPU上几个变量的一些“数学”函数。我决定使用Thrust及其zip_iterator
将变量打包到元组中,并将我的数学函数实现为函数for_each
。但是我希望有一个可以计算不同“数学”功能的通用功能。所以,我需要在函数中传递这个函子。
我认为,要完成这项任务,我应该实现一些具有不同版本operator()(Tuple t)
的仿函数的简单层次结构(使用唯一的基类)。例如,仿函数可以是这样的:
struct Func {
template <typename Tuple>
__host__ __device__
void operator()(Tuple arg) {
thrust::get<1>(arg) = 0;
}
};
strust f1 : public Func {
...
};
strust f2 : public Func {
...
};
问题是如何正确地将所需的函子传递给函数,以及如何定义这样的函数?这个功能可以是:
thrust::host_vector evaluateFunction(Func func, thrust::host_vector point) {
thrust::host_vector result(point.size());
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(point.begin(), result.begin())),
thrust::make_zip_iterator(thrust::make_tuple(point.end(), result.end())),
func);
return result;
}
但有了这样的定义,我无法将f1
或f2
传递给它。我该如何正确定义?
答案 0 :(得分:1)
似乎您希望将用户定义或用户可选择的函数传递给推力,以便在仿函数中进行评估。基于此,我认为一个可能的答案与发布的here非常相似,但我会做一些其他的评论。
thrust::device_vector
使用的对象基本上是不可能,因为It is not allowed to pass as an argument to a __global__
function an object of a class with virtual functions.虽然它并不完全明显,但如果我在主机上创建了一个合适的对象数组,然后尝试在thrust::device_vector
中多态地使用它们,那么这实际上就是我要做的。至少,我无法在丛林中战斗。当然,您可以在设备代码中使用多态,假设在设备上正确创建了对象,以便可以正确分配其虚拟功能表。 This question and comments也可能是有意义的。如果您想查看在设备对象上使用多态的示例,请查看我的答案here。它演示了使用对象本身来定义您希望对其执行的功能的想法。 (虽然,我认为这不是你的想法。)__device__
function in host code.这种限制可以通过调用“初始化内核”来解决,该初始化内核填充了设备函数指针的使用表以供使用在设备代码中,但我认为净效应并不比我在下面3中提出的要好。这是一个展示最后一个想法的例子:
#include <thrust/device_vector.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/for_each.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <math.h>
__host__ __device__ float f1(float x)
{
return sinf(x);
}
__host__ __device__ float f2(float x)
{
return cosf(x);
}
struct select_functor
{
unsigned fn;
select_functor(unsigned _fn) : fn(_fn) {};
template <typename Tuple>
__host__ __device__
void operator()(const Tuple &t) {
if (fn == 1) thrust::get<1>(t) = f1(thrust::get<0>(t));
else if (fn == 2) thrust::get<1>(t) = f2(thrust::get<0>(t));
else thrust::get<1>(t) = 0;
}
};
int main(void)
{
unsigned ufn = 1;
const unsigned N = 8;
thrust::device_vector<float> data(N), result(N);
// initilaize to some values
thrust::sequence(data.begin(), data.end(), 0.0f, (float)(6.283/(float)N));
std::cout<< "x: " << std::endl;
thrust::copy(data.begin(), data.end(), std::ostream_iterator<float>(std::cout, " "));
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn));
std::cout<< std::endl << "sin(x): " << std::endl;
thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " "));
ufn = 2;
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(data.begin(), result.begin())),thrust::make_zip_iterator(thrust::make_tuple(data.end(),result.end())),select_functor(ufn));
std::cout<< std::endl << "cos(x): " << std::endl;
thrust::copy(result.begin(), result.end(), std::ostream_iterator<float>(std::cout, " "));
std::cout<< std::endl;
return 0;
}